!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||


 module forcing_s_interior 3,10

!BOP
! !MODULE: forcing_s_interior
!
! !DESCRIPTION:
!  Contains routines and variables used for determining the
!  interior salinity restoring.
!
! !REVISION HISTORY:
!  SVN:$Id: forcing_s_interior.F90 12674 2008-10-31 22:21:32Z njn01 $
!
! !USES:

   use kinds_mod
   use blocks
   use domain
   use constants
   use io
   use forcing_tools
   use time_management
   use prognostic
   use grid
   use exit_mod

   implicit none
   private
   save

! !PUBLIC MEMBER FUNCTIONS:

   public :: init_s_interior,      &
              get_s_interior_data, &
              set_s_interior

! !PUBLIC DATA MEMBERS:

   real (r8), public ::       &! public for use in restart
      s_interior_interp_last   ! time last interpolation done

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  internal module variables
!
!-----------------------------------------------------------------------

   real (r8), dimension(:,:,:,:,:), allocatable :: &
      S_INTERIOR_DATA  ! data to use for interior restoring

   real (r8), dimension(:,:,:), allocatable :: &
      S_RESTORE_RTAU   !  inverse restoring timescale for
                       !  spatially-varying restoring

   integer (int_kind), dimension(:,:,:), allocatable :: &
      S_RESTORE_MAX_LEVEL ! maximum level for applying variable
                          ! interior restoring

   real (r8), dimension(12) :: &
      s_interior_data_time

   real (r8), dimension(20) :: &
      s_interior_data_renorm   ! factors to convert data to model units

   real (r8) ::               &
      s_interior_data_inc,    &! time increment between values of forcing data
      s_interior_data_next,   &! time to be used for the next value of forcing data that is needed
      s_interior_data_update, &! time when new forcing value to be added to interpolation set
      s_interior_interp_inc,  &! time increment between interpolation
      s_interior_interp_next, &! time next interpolation to be done
      s_interior_restore_tau, &! restoring timescale
      s_interior_restore_rtau  ! reciprocal of restoring timescale

   integer (int_kind) ::            &
      s_interior_interp_order,      &! order of temporal interpolation
      s_interior_data_time_min_loc, &! index of x_data_time with the minimum forcing time
      s_interior_restore_max_level

   character (char_len) ::    &
      s_interior_data_type,   &! keyword for period of forcing data
      s_interior_filename,    &! name of file containing forcing data
      s_interior_file_fmt,    &! format (bin or nc) of forcing file
      s_interior_interp_freq, &! keyword for period of temporal interpolation
      s_interior_interp_type, &!
      s_interior_data_label,  &!
      s_interior_formulation, &!
      s_interior_restore_filename, &!
      s_interior_restore_file_fmt   !

   character (char_len), dimension(:), allocatable :: &
      s_interior_data_names    ! names for required input data fields

   integer (int_kind), dimension(:), allocatable :: &
      s_interior_bndy_loc,    &! location and field type for ghost
      s_interior_bndy_type     !    cell updates

   logical (log_kind) :: &
      s_interior_variable_restore

!EOC
!***********************************************************************

 contains

!***********************************************************************
!BOP
! !IROUTINE: init_s_interior
! !INTERFACE:


 subroutine init_s_interior 1,71

! !DESCRIPTION:
!  Initializes salinity interior forcing by either calculating or
!  reading in the 3D salinity.  Also performs initial book-keeping
!  concerning when new data is needed for the temporal interpolation
!  and when the forcing will need to be updated.
!
! !REVISION HISTORY:
!  same as module

!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

   integer (int_kind) :: &
      n,                 &!
      nml_error           ! namelist i/o error flag

   character (char_len) :: &
      forcing_filename,    &! final filename for forcing data
      long_name             ! long name for input data

   type (datafile) :: &
      s_int_data_file  ! data file descriptor for s interior data

   type (io_field_desc) :: &
      s_int_data_in    ! io field descriptor for input salinity data

   type (io_dim) :: &
      i_dim, j_dim, &! dimension descriptors for horiz dimensions
      k_dim          ! dimension descriptor  for vertical levels

   namelist /forcing_s_interior_nml/ s_interior_data_type,            &
        s_interior_data_inc,         s_interior_interp_type,          &
        s_interior_interp_freq,      s_interior_interp_inc,           &
        s_interior_restore_tau,      s_interior_filename,             &
        s_interior_file_fmt,         s_interior_restore_max_level,    &
        s_interior_data_renorm,      s_interior_formulation,          &
        s_interior_variable_restore, s_interior_restore_filename,     &
        s_interior_restore_file_fmt

!-----------------------------------------------------------------------
!
!  read interior S namelist input after setting default values.
!
!-----------------------------------------------------------------------

   s_interior_formulation    = 'restoring'
   s_interior_data_type      = 'none'
   s_interior_data_inc       = 1.e20_r8
   s_interior_interp_type    = 'nearest'
   s_interior_interp_freq    = 'never'
   s_interior_interp_inc     = 1.e20_r8
   s_interior_restore_tau    = 1.e20_r8
   s_interior_filename       = 'unknown-s_interior'
   s_interior_file_fmt       = 'bin'
   s_interior_restore_max_level = 0
   s_interior_data_renorm    = c1
!  s_interior_data_renorm    = 1.e-3_r8  !  convert from psu to g/g
   s_interior_variable_restore  = .false.
   s_interior_restore_filename  = 'unknown-s_interior_restore'
   s_interior_restore_file_fmt  = 'bin'

   if (my_task == master_task) then
      open (nml_in, file=nml_filename, status='old', iostat=nml_error)
      if (nml_error /= 0) then
         nml_error = -1
      else
         nml_error =  1
      endif
      !*** keep reading until find right namelist
      do while (nml_error > 0)
         read(nml_in, nml=forcing_s_interior_nml,iostat=nml_error)
      end do
      if (nml_error == 0) close(nml_in)
   end if

   call broadcast_scalar(nml_error, master_task)
   if (nml_error /= 0) then
     call exit_POP(sigAbort,'ERROR: reading forcing_s_interior_nml')
   endif

   call broadcast_scalar(s_interior_formulation,       master_task)
   call broadcast_scalar(s_interior_data_type,         master_task)
   call broadcast_scalar(s_interior_data_inc,          master_task)
   call broadcast_scalar(s_interior_interp_type,       master_task)
   call broadcast_scalar(s_interior_interp_freq,       master_task)
   call broadcast_scalar(s_interior_interp_inc,        master_task)
   call broadcast_scalar(s_interior_restore_tau,       master_task)
   call broadcast_scalar(s_interior_filename,          master_task)
   call broadcast_scalar(s_interior_file_fmt,          master_task)
   call broadcast_scalar(s_interior_restore_max_level, master_task)
   call broadcast_scalar(s_interior_variable_restore,  master_task)
   call broadcast_scalar(s_interior_restore_filename,  master_task)
   call broadcast_scalar(s_interior_restore_file_fmt,  master_task)
   call broadcast_array (s_interior_data_renorm,       master_task)

!-----------------------------------------------------------------------
!
!  convert data_type to 'monthly-calendar' if input is 'monthly'
!
!-----------------------------------------------------------------------

   if (s_interior_data_type == 'monthly') &
       s_interior_data_type = 'monthly-calendar'

!-----------------------------------------------------------------------
!
!  calculate inverse of restoring time scale and convert to seconds.
!
!-----------------------------------------------------------------------

   s_interior_restore_rtau = c1/(seconds_in_day*s_interior_restore_tau)

!-----------------------------------------------------------------------
!
!  convert interp_type to corresponding integer value.
!
!-----------------------------------------------------------------------

   select case (s_interior_interp_type)
   case ('nearest')
      s_interior_interp_order = 1

   case ('linear')
      s_interior_interp_order = 2

   case ('4point')
      s_interior_interp_order = 4

   case default
      call exit_POP(sigAbort, &
         'init_s_interior: Unknown value for s_interior_interp_type')

   end select

!-----------------------------------------------------------------------
!
!  set values of the interior S array (S_INTERIOR_DATA)
!  depending on the type of S data.
!
!-----------------------------------------------------------------------

   select case (s_interior_data_type)

   case ('none')

      !*** no interior forcing, therefore no interpolation in time is
      !*** needed, nor are there any new values to be used.

      s_interior_data_next = never
      s_interior_data_update = never
      s_interior_interp_freq = 'never'

   case ('annual')

      !*** annual mean climatological salinity (read in from a file)
      !*** constant in time, therefore no new values will be needed

      allocate(S_INTERIOR_DATA(nx_block,ny_block,km, &
                               max_blocks_clinic,1))

      allocate(s_interior_data_names(1), &
               s_interior_bndy_loc  (1), &
               s_interior_bndy_type (1))

      S_INTERIOR_DATA = c0
      s_interior_data_names(1) = 'SALINITY'
      s_interior_bndy_loc  (1) = field_loc_center
      s_interior_bndy_type (1) = field_type_scalar

      forcing_filename = s_interior_filename

      s_int_data_file = construct_file(s_interior_file_fmt,            &
                                    full_name=trim(forcing_filename),  &
                                    record_length=rec_type_dbl,        &
                                    recl_words=nx_global*ny_global)

      call data_set(s_int_data_file, 'open_read')

      i_dim = construct_io_dim('i', nx_global)
      j_dim = construct_io_dim('j', ny_global)
      k_dim = construct_io_dim('k', km)

      s_int_data_in = construct_io_field(                      &
                         trim(s_interior_data_names(1)),       &
                         dim1=i_dim, dim2=j_dim, dim3=k_dim,             &
                         field_loc = s_interior_bndy_loc(1),   &
                         field_type = s_interior_bndy_type(1), &
                         d3d_array = S_INTERIOR_DATA(:,:,:,:,1))

      call data_set (s_int_data_file, 'define', s_int_data_in)
      call data_set (s_int_data_file, 'read',   s_int_data_in)
      call data_set (s_int_data_file, 'close')
      call destroy_io_field(s_int_data_in)
      call destroy_file(s_int_data_file)

      if (s_interior_data_renorm(1) /= c1) &
         S_INTERIOR_DATA = S_INTERIOR_DATA*s_interior_data_renorm(1)

      s_interior_data_next = never
      s_interior_data_update = never
      s_interior_interp_freq = 'never'

      if (my_task == master_task) then
         write(stdout,blank_fmt)
         write(stdout,'(a30,a)') ' Interior S Annual file read: ', &
                                 trim(forcing_filename)
      endif

   case ('monthly-equal','monthly-calendar')

      !*** monthly mean climatological interior salinity
      !*** all 12 months are read from a file. interpolation order
      !*** may be specified with namelist input.

      allocate(S_INTERIOR_DATA(nx_block,ny_block,km,    &
                               max_blocks_clinic,0:12))

      allocate(s_interior_data_names(12), &
               s_interior_bndy_loc  (12), &
               s_interior_bndy_type (12))

      S_INTERIOR_DATA = c0

      call find_forcing_times(           s_interior_data_time,         &
                 s_interior_data_inc,    s_interior_interp_type,       &
                 s_interior_data_next,   s_interior_data_time_min_loc, &
                 s_interior_data_update, s_interior_data_type)

      forcing_filename = s_interior_filename
      s_int_data_file = construct_file(s_interior_file_fmt,            &
                                    full_name=trim(forcing_filename),  &
                                    record_length=rec_type_dbl,        &
                                    recl_words=nx_global*ny_global)

      call data_set(s_int_data_file, 'open_read')

      i_dim = construct_io_dim('i', nx_global)
      j_dim = construct_io_dim('j', ny_global)
      k_dim = construct_io_dim('k', km)

      do n = 1, 12
         write(s_interior_data_names(n),'(a9,i2)') 'SALINITY ',n
         s_interior_bndy_loc (n) = field_loc_center
         s_interior_bndy_type(n) = field_type_scalar

         s_int_data_in = construct_io_field( &
                         trim(s_interior_data_names(n)),       &
                         dim1=i_dim, dim2=j_dim, dim3=k_dim,             &
                         field_loc = s_interior_bndy_loc(n),   &
                         field_type = s_interior_bndy_type(n), &
                         d3d_array = S_INTERIOR_DATA(:,:,:,:,n))

         call data_set (s_int_data_file, 'define', s_int_data_in)
         call data_set (s_int_data_file, 'read',   s_int_data_in)
         call destroy_io_field(s_int_data_in)
      enddo

      call data_set (s_int_data_file, 'close')
      call destroy_file(s_int_data_file)

      if (s_interior_data_renorm(1) /= c1) &
         S_INTERIOR_DATA = S_INTERIOR_DATA*s_interior_data_renorm(1)

      if (my_task == master_task) then
         write(stdout,blank_fmt)
         write(stdout,'(a31,a)') ' Interior S Monthly file read: ', &
                                 trim(forcing_filename)
      endif

   case ('n-hour')

      !*** interior salinity specified every n-hours, where
      !*** the n-hour increment (s_interior_data_inc) should be
      !*** specified with namelist input. Only as many times as are
      !*** necessary based on the order of the temporal interpolation
      !*** scheme reside in memory at any given time.

      allocate(S_INTERIOR_DATA(nx_block,ny_block,km,max_blocks_clinic, &
                                         0:s_interior_interp_order))

      allocate(s_interior_data_names(1), &
               s_interior_bndy_loc  (1), &
               s_interior_bndy_type (1))

      S_INTERIOR_DATA = c0
      s_interior_data_names(1) = 'SALINITY'
      s_interior_bndy_loc  (1) = field_loc_center
      s_interior_bndy_type (1) = field_type_scalar

      call find_forcing_times(           s_interior_data_time,         &
                 s_interior_data_inc,    s_interior_interp_type,       &
                 s_interior_data_next,   s_interior_data_time_min_loc, &
                 s_interior_data_update, s_interior_data_type)

      do n = 1, s_interior_interp_order
         call get_forcing_filename(forcing_filename,        &
                                   s_interior_filename,     &
                                   s_interior_data_time(n), &
                                   s_interior_data_inc)

         s_int_data_file = construct_file(s_interior_file_fmt,         &
                                    full_name=trim(forcing_filename),  &
                                    record_length=rec_type_dbl,        &
                                    recl_words=nx_global*ny_global)

         call data_set(s_int_data_file, 'open_read')

         i_dim = construct_io_dim('i', nx_global)
         j_dim = construct_io_dim('j', ny_global)
         k_dim = construct_io_dim('k', km)

         s_int_data_in = construct_io_field(                   &
                         trim(s_interior_data_names(1)),       &
                         dim1=i_dim, dim2=j_dim, dim3=k_dim,             &
                         field_loc = s_interior_bndy_loc(1),   &
                         field_type = s_interior_bndy_type(1), &
                         d3d_array = S_INTERIOR_DATA(:,:,:,:,n))

         call data_set (s_int_data_file, 'define', s_int_data_in)
         call data_set (s_int_data_file, 'read',   s_int_data_in)
         call data_set (s_int_data_file, 'close')
         call destroy_io_field(s_int_data_in)
         call destroy_file(s_int_data_file)

         if (my_task == master_task) then
            write(stdout,blank_fmt)
            write(stdout,'(a30,a)') ' Interior S n-hour file read: ', &
                                    trim(forcing_filename)
         endif
      enddo

      if (s_interior_data_renorm(1) /= c1) &
         S_INTERIOR_DATA = S_INTERIOR_DATA*s_interior_data_renorm(1)

   case default

     call exit_POP(sigAbort, &
              'init_s_interior: Unknown value for s_interior_data_type')

   end select

!-----------------------------------------------------------------------
!
!  now check interpolation period (s_interior_interp_freq) to set the
!    time for the next temporal interpolation (s_interior_interp_next).
!
!  if no interpolation is to be done, set next interpolation time
!    to a large number so the interior S update test in routine
!    get_forcing_data will always be false.
!
!  if interpolation is to be done every n-hours, find the first
!    interpolation time greater than the current time.
!
!  if interpolation is to be done every timestep, set next interpolation
!    time to a large negative number so the interior S update
!    test in routine set_surface_forcing will always be true.
!
!-----------------------------------------------------------------------

   select case (s_interior_interp_freq)

   case ('never')

     s_interior_interp_next = never
     s_interior_interp_last = never
     s_interior_interp_inc  = c0

   case ('n-hour')
     call find_interp_time(s_interior_interp_inc,s_interior_interp_next)

   case ('every-timestep')

     s_interior_interp_next = always
     s_interior_interp_inc  = c0

   case default

     call exit_POP(sigAbort, &
        'init_s_interior: Unknown value for s_interior_interp_freq')

   end select

   if(nsteps_total == 0) s_interior_interp_last = thour00

!-----------------------------------------------------------------------
!
!  allocate and read in arrays used for variable interior restoring
!    if necessary.
!
!-----------------------------------------------------------------------

   if (s_interior_variable_restore) then

      allocate(S_RESTORE_MAX_LEVEL(nx_block,ny_block,max_blocks_clinic), &
                    S_RESTORE_RTAU(nx_block,ny_block,max_blocks_clinic))

      forcing_filename = s_interior_restore_filename

      s_int_data_file = construct_file(s_interior_restore_file_fmt,    &
                                    full_name=trim(forcing_filename),  &
                                    record_length=rec_type_dbl,        &
                                    recl_words=nx_global*ny_global)

      call data_set(s_int_data_file, 'open_read')

      i_dim = construct_io_dim('i', nx_global)
      j_dim = construct_io_dim('j', ny_global)

      s_int_data_in = construct_io_field('S_RESTORE_MAX_LEVEL',  &
                       dim1=i_dim, dim2=j_dim,                             &
                       field_loc = field_loc_center,             &
                       field_type = field_type_scalar,           &
                       d2d_array = S_RESTORE_RTAU)

      call data_set (s_int_data_file, 'define', s_int_data_in)
      call data_set (s_int_data_file, 'read',   s_int_data_in)
      S_RESTORE_MAX_LEVEL = nint(S_RESTORE_RTAU)
      call destroy_io_field(s_int_data_in)

      s_int_data_in = construct_io_field('S_RESTORE_RTAU',       &
                       dim1=i_dim, dim2=j_dim,                             &
                       field_loc = field_loc_center,             &
                       field_type = field_type_scalar,           &
                       d2d_array = S_RESTORE_RTAU)

      call data_set (s_int_data_file, 'define', s_int_data_in)
      call data_set (s_int_data_file, 'read',   s_int_data_in)
      S_RESTORE_RTAU = S_RESTORE_RTAU/seconds_in_day ! convert days to secs
      call destroy_io_field(s_int_data_in)
      call data_set (s_int_data_file, 'close')
      call destroy_file(s_int_data_file)

   endif

!-----------------------------------------------------------------------
!
!  echo forcing options to stdout.
!
!-----------------------------------------------------------------------

   s_interior_data_label = 'Interior Salinity Forcing'
   if (s_interior_variable_restore .and. my_task == master_task) &
      write(stdout,"('Variable Interior Salinity Restoring enabled')")
   call echo_forcing_options(s_interior_data_type,                     &
                       s_interior_formulation, s_interior_data_inc,    &
                       s_interior_interp_freq, s_interior_interp_type, &
                       s_interior_interp_inc, s_interior_data_label)

!-----------------------------------------------------------------------
!EOC

 end subroutine init_s_interior

!***********************************************************************
!BOP
! !IROUTINE: get_s_interior_data
! !INTERFACE:


 subroutine get_s_interior_data 1,4

! !DESCRIPTION:
!  Determines whether new interior forcing data is required and
!  reads the data if necessary.  Also interpolates data to current
!  time if required.
!
! !REVISION HISTORY:
!  same as module

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------
!
!  check if new data is necessary for interpolation.  if yes, then
!    shuffle indices in SSS_RESTORE and s_interior_data_time arrays
!    and read in new data if necessary ('n-hour' case).  also
!    increment values of s_interior_data_time_min_loc,
!    s_interior_data_next and s_interior_data_update. note that no new
!    data is necessary for 'analytic' and 'annual' cases.
!
!-----------------------------------------------------------------------

   select case(s_interior_data_type)

   case ('monthly-equal','monthly-calendar')

      s_interior_data_label = 'S_INTERIOR Monthly'
      if (thour00 >= s_interior_data_update) then
         call update_forcing_data(             s_interior_data_time,   &
                 s_interior_data_time_min_loc, s_interior_interp_type, &
                 s_interior_data_next,         s_interior_data_update, &
                 s_interior_data_type,         s_interior_data_inc,    &
                 S_INTERIOR_DATA(:,:,:,:,1:12),s_interior_data_renorm, &
                 s_interior_data_label,        s_interior_data_names,  &
                 s_interior_bndy_loc,          s_interior_bndy_type,   &
                 s_interior_filename,          s_interior_file_fmt)
      endif

      if (thour00 >= s_interior_interp_next .or. nsteps_run==0) then
         call interpolate_forcing(S_INTERIOR_DATA(:,:,:,:,0),          &
                                  S_INTERIOR_DATA(:,:,:,:,1:12),       &
                 s_interior_data_time,         s_interior_interp_type, &
                 s_interior_data_time_min_loc, s_interior_interp_freq, &
                 s_interior_interp_inc,        s_interior_interp_next, &
                 s_interior_interp_last,       nsteps_run)

         if (nsteps_run /= 0) s_interior_interp_next = &
                              s_interior_interp_next + &
                              s_interior_interp_inc
      endif

   case('n-hour')

      s_interior_data_label = 'S_INTERIOR n-hour'
      if (thour00 >= s_interior_data_update) then
         call update_forcing_data(             s_interior_data_time,   &
                 s_interior_data_time_min_loc, s_interior_interp_type, &
                 s_interior_data_next,         s_interior_data_update, &
                 s_interior_data_type,         s_interior_data_inc,    &
                 S_INTERIOR_DATA(:,:,:,:,1:s_interior_interp_order),   &
                 s_interior_data_renorm,                               &
                 s_interior_data_label,        s_interior_data_names,  &
                 s_interior_bndy_loc,          s_interior_bndy_type,   &
                 s_interior_filename,          s_interior_file_fmt)
      endif

      if (thour00 >= s_interior_interp_next .or. nsteps_run==0) then
         call interpolate_forcing(S_INTERIOR_DATA(:,:,:,:,0),          &
                 S_INTERIOR_DATA(:,:,:,:,1:s_interior_interp_order),   &
                 s_interior_data_time,         s_interior_interp_type, &
                 s_interior_data_time_min_loc, s_interior_interp_freq, &
                 s_interior_interp_inc,        s_interior_interp_next, &
                 s_interior_interp_last,       nsteps_run)

         if (nsteps_run /= 0) s_interior_interp_next = &
                              s_interior_interp_next + &
                              s_interior_interp_inc
      endif

   end select

!-----------------------------------------------------------------------
!EOC

 end subroutine get_s_interior_data

!***********************************************************************
!BOP
! !IROUTINE: set_s_interior
! !INTERFACE:


 subroutine set_s_interior(k,this_block,S_SOURCE) 1

! !DESCRIPTION:
!  Computes interior salinity forcing term (DS\_INTERIOR) using
!  updated and interpolated data.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   integer (int_kind), intent(in) :: &
      k     ! vertical level index

   type (block), intent(in) :: &
      this_block   ! block information for this block

! !OUTPUT PARAMETERS:

   real (r8), dimension(nx_block,ny_block), intent(inout) :: &
      S_SOURCE    ! source terms for salinity forcing - add restoring
                  ! to any other source terms

!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

   integer (int_kind) ::  &
      bid,                &! local block address for this block
      now                  ! index for location of interpolated data

   real (r8), dimension(nx_block,ny_block) :: &
      DS_INTERIOR    ! interior salinity restoring term for this block
                     ! and level

!-----------------------------------------------------------------------
!
!  do interior restoring if required (no restoring at surface for any)
!
!-----------------------------------------------------------------------

   if (s_interior_data_type /= 'none' .and. k > 1) then

!-----------------------------------------------------------------------
!
!     set index for location of interpolated data.
!
!-----------------------------------------------------------------------

      select case(s_interior_data_type)

      case('annual')
         now = 1

      case ('monthly-equal','monthly-calendar')
         now = 0

      case('n-hour')
         now = 0

      end select

!-----------------------------------------------------------------------
!
!     now compute restoring
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      if (s_interior_variable_restore) then
         DS_INTERIOR = S_RESTORE_RTAU(:,:,bid)*                &
                       merge((S_INTERIOR_DATA(:,:,k,bid,now) - &
                              TRACER(:,:,k,2,curtime,bid)),    &
                             c0, k <= S_RESTORE_MAX_LEVEL(:,:,bid))
      else
         if (k <= s_interior_restore_max_level) then
            DS_INTERIOR = s_interior_restore_rtau*         &
                         (S_INTERIOR_DATA(:,:,k,bid,now) - &
                          TRACER(:,:,k,2,curtime,bid))
         else
            DS_INTERIOR = c0
         endif
      endif

      !*** add restoring term to other source terms

      S_SOURCE = S_SOURCE + DS_INTERIOR

   endif ! k=1

!-----------------------------------------------------------------------
!EOC

 end subroutine set_s_interior

!***********************************************************************

 end module forcing_s_interior

!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||