Hello,

At Matt Harrison's suggestion, I am providing the sponge code for
anyone who may need it. This will replace the existing code in

mom4/ocean_param/sources/sponge/ocean_sponges.F90

of the mom4_beta2 release of Oct. 2002. The comments at the top of the
file will explain its use.

Matt will merge this code in the next  release of mom4 but till then
you are welcome to use it. If you have any problems/questions please
let me know.

Swathi 
module ocean_sponge_mod
!-----------------------------------------------------------------------
!                   GNU General Public License                        
! This file is a part of MOM.                                                          
       
!                                                                      
! MOM 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; either version 2 of   
! the License, or (at your option) any later version.                 
!                                                                      
! MOM 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.                                           
!                                                                      
! For the full text of the GNU General Public License,                
! write to: Free Software Foundation, Inc.,                           
!           675 Mass Ave, Cambridge, MA 02139, USA.                   
! or see:   http://www.gnu.org/licenses/gpl.html                      
!-----------------------------------------------------------------------
!
!<CONTACT EMAIL="[EMAIL PROTECTED]"> P.S.Swathi 
!</CONTACT>
!
!<CONTACT EMAIL="[EMAIL PROTECTED]"> Bonnie Samuels 
!</CONTACT>
!
!<CONTACT EMAIL="[EMAIL PROTECTED]"> R.W. Hallberg 
!</CONTACT>
!
!<OVERVIEW>
! Thickness weighted tracer tendency [tracer*meter/sec] from sponges.
!</OVERVIEW>
!
!<DESCRIPTION>
! Based on the code of bls and rwh. Sponge time rates are fixed in
! time but sponge values can vary in time. Blindly apply sponge.
! Some redundant calculations are send_data calls to avoid
! problems in diag_manager..Hard coded for n=1 temp and n=2 salt.
!
! This module applies sponges to tracers. The sponges
! can occur at any location and with any distribution in the domain, and
! with any time step and damping rate.  Sponges occur where positive
! inverse restore times occur in the field passed to sponge_init.  An
! array of tracer tendencies due to the sponges is augmented through a
! call to sponge_tracer_source.  The array of tracer tendencies must be
! reset to zero between calls.
!
! Different damping rates (but constatnt in time) can be specified for each field.
! No sponges are applied to fields for
! which uniformly zero.
!
! The user is responsible for providing  time-dependent data on
! the model grid of values towards which the tracers are being driven.
!</DESCRIPTION>
!
!<NAMELIST NAME="ocean_sponge_nml">
!  <DATA NAME="restoretime_temp_path" TYPE="character*128">
!  Path where the restore time field for temp is located
!  </DATA> 
!  <DATA NAME="restoretime_salt_path" TYPE="character*128">
!  Path where the restore time field for salt is located
!  </DATA> 
!  <DATA NAME="restoretime_temp_name" TYPE="character*128">
!  Name of the restore time field for temp in the netcdf file
!  </DATA>
!  <DATA NAME="restoretime_salt_name" TYPE="character*128">
!  Name of the restore time field for salt in the netcdf file
!  </DATA> 
!  <DATA NAME="sponge_temp_path" TYPE="character*128">
!  Path where the sponge potential temp field is located
!  </DATA> 
!  <DATA NAME="sponge_temp_name" TYPE="character*128">
!  Name of the sponge potential temp field within the netcdf file 
!  </DATA> 
!  <DATA NAME="sponge_salt_path" TYPE="character*128">
!  Path where the sponge salinity field is located
!  </DATA> 
!  <DATA NAME="sponge_salt_name" TYPE="character*128">
!  Name of the sponge salinity field within the netcdf file 
!  </DATA> 
!  <DATA NAME="num_sponges" TYPE="integer">
!  Number of tracers that are damped to the sponge
!  </DATA> 
!  <DATA NAME="target_date" TYPE="time_type">
!  Time that values within sponge are damped towards 
!  </DATA> 
!</NAMELIST>

use fms_mod, only: write_version_number, error_mesg, FATAL
use time_manager_mod, only: time_type, set_date
use time_manager_mod, only: operator( + ), operator(-), operator( // ), operator(>), 
operator(==), operator(<=)
use time_interp_external_mod, only: time_interp_external, init_external_field
use diag_manager_mod, only : register_diag_field, send_data
use field_manager_mod, only : method_type, default_method
!
use mpp_io_mod, only: mpp_open, mpp_close, mpp_read
use mpp_io_mod, only: MPP_RDONLY, MPP_NETCDF, MPP_MULTI, MPP_ASCII, MPP_SINGLE
use mpp_io_mod, only: fieldtype, mpp_get_atts, mpp_get_info, mpp_get_fields
use mpp_mod, only: mpp_chksum, mpp_error, WARNING
use fms_mod, only : lowercase

use ocean_domains_mod, only: iscomp, iecomp, jscomp, jecomp, halo
use ocean_tmngr_mod, only : tau, taum1, model_time
implicit none
  type, public :: ocean_sponge_type
     character(len=32) :: name, units, tracer_name
     character(len=128) :: longname
     integer :: sponge_id                      ! index to flux_manager
     integer :: tracer_id                    ! index to tracer_manager 
     integer :: num_inputs
     real    :: convert
     character(len=32) :: input_name
     character(len=128) :: input_file
     integer :: input_id                    ! index to time_interp_external_mod 
     integer :: diag_id ! diagnostics manager ids
     real :: range(2)
     integer :: num_methods
     type(method_type)  :: methods
  end type ocean_sponge_type
  type(ocean_sponge_type), public, dimension(:), allocatable :: tracer_sponge(:)
  type(ocean_sponge_type),public  :: default_sponge
!

private
integer,allocatable :: num_col(:)       ! The number of columns which are subject to 
damping within this domain.
integer, allocatable :: isp(:,:), jsp(:,:)   ! The indices of each column.

real, allocatable :: sponge_val(:,:) ! The values that are being damped towards, in 
the units
                                         ! of the respective fields.  The 2 indices 
are (in order):
                                         ! the column number and the vertical levels 


real, allocatable :: inv_damp(:,:,:), damp_coef(:,:,:) ! The inverse damping rates for 
each field, and
                                                       ! the related coefficint 
{(1-exp(-dt/rate))/dt} based on
                                                       ! the previous time step. 
real,allocatable :: sponge_mask(:,:,:,:) ! sponge_mask.

logical, allocatable :: sponge_anywhere(:) ! Denotes whether each field has nonzero 
inverse damping
                                           ! rates anywhere in this domain.
logical :: first_call = .true.

public ocean_sponge_init
public sponge_tracer_source



character(len=256) :: version = &
 '=>Using: ocean_sponges.F90 ($Id: ocean_sponges.F90,v 1.1.1.1 2002/12/23 11:35:30 
swathi Exp $)'
character (len=128) :: tagname = &
 '$Name:  $'

logical :: module_is_initialized = .FALSE.

contains


!#######################################################################
! <SUBROUTINE NAME="ocean_sponge_init">
!
! <DESCRIPTION>
! This subroutine is intended to be used to initialize the sponges.
! Everything in this subroutine is a user prototype, and should be replacable.
! </DESCRIPTION>
!
! <IN NAME="dt" UNITS="seconds" TYPE="real">
! The tracer timestep (or the time step for the sponges), in seconds
! </IN>
subroutine ocean_sponge_init(dt)

  use mpp_mod, only: stdout, stdlog

  use ocean_domains_mod, only: iscomp, iecomp, jscomp, jecomp, halo, local_domain
  use ocean_grids_mod, only: nk, tmask,tracer_axes
  use ocean_tmngr_mod

  real,intent(in) :: dt   

  real,allocatable :: inv_resttime(:,:,:,:) ! The inverse damping rates in s-1.
  logical :: error=.false.
  integer :: i, j, k, nt, kk, k_found, col, nf, ll
  character*128 :: restoretime_temp_path='',restoretime_temp_name='coeff'
  character*128 :: restoretime_salt_path='',restoretime_salt_name='coeff'
  character*128 :: sponge_temp_path='',sponge_temp_name='temp'
  character*128 :: sponge_salt_path='',sponge_salt_name='salt'
!
  character(len=32) :: name
  integer :: unit_t, unit_s, ioun, io_status
  integer :: ndim, nvar, natt, ntime, llen
  integer :: num_sponges = 2
  type(fieldtype), allocatable, dimension(:) :: fields
  logical :: verbose_flag = .false.
  real,parameter :: missing = -1.0e10

  namelist /ocean_sponge_nml/ restoretime_temp_path,restoretime_temp_name,&
   restoretime_salt_path,restoretime_salt_name, &
   sponge_temp_path,sponge_temp_name,sponge_salt_path,sponge_salt_name,&
   num_sponges

  if ( module_is_initialized ) call &
       error_mesg( 'ocean_sponge_init', &
       'attempted reinitialization', &
       FATAL )

  module_is_initialized = .TRUE.

  call write_version_number( version, tagname )

  ! provide for namelist over-ride of defaults 
  call mpp_open (ioun, 'input.nml', action=MPP_RDONLY, form=MPP_ASCII)
  read  (ioun, ocean_sponge_nml,iostat=io_status)
!  write (stdlog(), ocean_sponge_nml)
  write (stdout(), ocean_sponge_nml)
  if (io_status .gt. 0) then
    call mpp_error(FATAL, '=>Error reading input.nml at ocean_sponge_nml')
  endif
  call mpp_close (ioun)
!
  allocate (inv_resttime(ij_bounds,nk,num_sponges)) 
  allocate (sponge_mask(ij_bounds,nk,num_sponges))
  allocate (num_col(num_sponges))
  allocate (inv_damp((iecomp-iscomp+1)*(jecomp-jscomp+1),num_sponges,nk))
  allocate (damp_coef((iecomp-iscomp+1)*(jecomp-jscomp+1),num_sponges,nk))
  allocate (isp((iecomp-iscomp+1)*(jecomp-jscomp+1),num_sponges))
  allocate (jsp((iecomp-iscomp+1)*(jecomp-jscomp+1),num_sponges))
  allocate (sponge_anywhere(num_sponges))
!
  inv_resttime(:,:,:,:) = 0.0
  sponge_mask(:,:,:,:) = 0.0
  sponge_anywhere(:) = .false.
  num_col(:) = 0
  isp(:,:) = 0
  jsp(:,:) = 0
  inv_damp(:,:,:) = 0.0
  damp_coef(:,:,:) = 0.0
!

  ! read the 3D restore time data
  ! restore time units are sec-1
   write (stdout(),*) ' Note:Reading Sponge restoring times from ', 
trim(restoretime_temp_path)
   call mpp_open (unit_t, trim(restoretime_temp_path), action=MPP_RDONLY, 
form=MPP_NETCDF,threading=MPP_MULTI,fileset=MPP_SINGLE)
   call mpp_get_info(unit_t, ndim, nvar, natt, ntime)
   allocate(fields(nvar))
   call mpp_get_fields(unit_t,fields)
   io_status = 0
   do i=1,nvar
     call mpp_get_atts(fields(i),name=name)
     if (lowercase(trim(name)) ==  lowercase(trim(restoretime_temp_name))) then
          call mpp_read(unit_t, fields(i),local_domain,inv_resttime(:,:,:,1))
          io_status=io_status+1      
     endif
   enddo
   if (io_status .eq. 0) then
     call mpp_error(FATAL, '=>Error reading sponge restoretime_temp')
   endif
   call mpp_close(unit_t)
   deallocate(fields)
!
   write (stdout(),*) ' Note:Reading Sponge restoring times from ', 
trim(restoretime_salt_path)
   call mpp_open (unit_s, trim(restoretime_salt_path), action=MPP_RDONLY, 
form=MPP_NETCDF,threading=MPP_MULTI,fileset=MPP_SINGLE)
   call mpp_get_info(unit_s, ndim, nvar, natt, ntime)
   allocate(fields(nvar))
   call mpp_get_fields(unit_s,fields)
   io_status = 0
   do i=1,nvar
     call mpp_get_atts(fields(i),name=name)
     if (lowercase(trim(name)) ==  lowercase(trim(restoretime_salt_name))) then
       call mpp_read(unit_s, fields(i),local_domain,inv_resttime(:,:,:,2))
       io_status=io_status+1
     endif
   enddo
   if (io_status .eq. 0) then
     call mpp_error(FATAL, '=>Error reading sponge restoretime_salt')
   endif
   call mpp_close(unit_s)
   deallocate(fields)
!
   do ll = 1,num_sponges  
! reset land points to zero
     do k=1,nk
       do j=jscomp,jecomp
         do i=iscomp,iecomp
           inv_resttime(i,j,k,ll)=inv_resttime(i,j,k,ll)*tmask(i,j,k)
           if (inv_resttime(i,j,k,ll) > 0) sponge_mask(i,j,k,ll)= 1.0
         enddo
       enddo
     enddo
     write (stdout(),*) 'll, Checksum: Original inv_resttime =', ll,mpp_chksum( 
inv_resttime(iscomp:iecomp,jscomp:jecomp,1:nk,ll))
  ! Count the columns that are in sponges
  ! May have to change this
     num_col(ll) = 0
     do j=jscomp,jecomp
       do i=iscomp,iecomp
         k_found = 0
         do k=1,nk
           if ((inv_resttime(i,j,k,ll) > 0.0) .and. (k_found == 0)) then
             num_col(ll) = num_col(ll) + 1
             k_found = 1
           endif
         enddo
       enddo
     enddo
!
     if (num_col(ll) == 0) then
       write(stdout(),*)'There are no sponges in this domain'
       sponge_anywhere(ll) = .false.
     else
       sponge_anywhere(ll) = .true.
       col = 1
       do j=jscomp,jecomp
         do i=iscomp,iecomp
           k_found = 0
           do kk=1,nk
             if ((inv_resttime(i,j,kk,ll) > 0.0) .and. (k_found == 0)) then
               k_found = 1
               isp(col,ll) = i
               jsp(col,ll) = j
               do k=1,nk
                 inv_damp(col,ll,k) = inv_resttime(i,j,k,ll)
               enddo
               col = col + 1
             endif
           enddo
         enddo
       enddo
     endif
     call calculate_damp_coef(dt, ll)
  enddo

!
  deallocate (inv_resttime)
! Get the sponge data fields
  allocate(tracer_sponge(num_sponges))
!
! Some default values
!
  default_sponge%name = 'none'
  default_sponge%longname = 'none'
  default_sponge%units = 'none'
  default_sponge%convert = 1.0
  default_sponge%input_name = 'none'
  default_sponge%input_file =  'none' 
  default_sponge%range = (/-1.0e10,1.0e10/)
  default_sponge%input_id = -1
  default_sponge%num_methods = 0
  default_sponge%methods%method_type = 'none'          
  default_sponge%diag_id = -1
!
  tracer_sponge = default_sponge
!
  tracer_sponge(1)%name = 'temp'
  tracer_sponge(1)%longname = 'Sponge target temperature'
  tracer_sponge(1)%units = 'deg C'
  tracer_sponge(1)%convert = 1.0
  tracer_sponge(1)%input_name = 'temp'
  tracer_sponge(1)%input_file =  trim(sponge_temp_path) 
  tracer_sponge(1)%range = (/-10,45/)
  tracer_sponge(1)%input_id = init_external_field(tracer_sponge(1)%input_file,&
                    tracer_sponge(1)%input_name,&
                    MPP_NETCDF,MPP_MULTI,local_domain,'deg_C',verbose_flag)
                   if(tracer_sponge(1)%input_id == -1) then 
                    call mpp_error(FATAL,'=>Error reading temp sponge field inside 
ocean_sponges_init')
                   endif
  tracer_sponge(1)%num_methods = 1
  tracer_sponge(1)%methods%method_type = 'sponge_temp'          
  tracer_sponge(1)%diag_id = 
register_diag_field('ocean_sponges',trim(tracer_sponge(1)%name)//'_sponge_data',&
                 
tracer_axes(1:3),model_time,tracer_sponge(1)%longname,tracer_sponge(1)%units,&
                 missing_value=missing,range=tracer_sponge(1)%range)  
!
  tracer_sponge(2)%name = 'salt'
  tracer_sponge(2)%longname = 'Sponge target salinity'
  tracer_sponge(2)%units = 'g/kg'
  tracer_sponge(2)%convert = 1.0
  tracer_sponge(2)%input_name = 'salt'
  tracer_sponge(2)%input_file =  trim(sponge_salt_path)
  tracer_sponge(2)%range = (/0,45/) 
  tracer_sponge(2)%input_id = init_external_field(tracer_sponge(2)%input_file,&
                    tracer_sponge(2)%input_name,&
                    MPP_NETCDF,MPP_MULTI,local_domain,'g/kg',verbose_flag)
                   if(tracer_sponge(2)%input_id == -1) then 
                    call mpp_error(FATAL,'=>Error reading salt sponge field inside 
ocean_sponges_init')
                   endif
  tracer_sponge(2)%num_methods = 1
  tracer_sponge(2)%methods%method_type = 'sponge_salt'
  tracer_sponge(2)%diag_id = 
register_diag_field('ocean_sponges',trim(tracer_sponge(2)%name)//'_sponge_data',&
                 
tracer_axes(1:3),model_time,tracer_sponge(2)%longname,tracer_sponge(2)%units,&
                 missing_value=missing,range=tracer_sponge(2)%range)

end subroutine ocean_sponge_init


!#######################################################################
! <SUBROUTINE NAME="sponge_tracer_source">
!
! <DESCRIPTION>
! This subroutine calculates thickness weighted time tendencies of the
! tracers due to the sponges.
! </DESCRIPTION>
!
! <IN NAME="t" UNITS="tracer" TYPE="real" DIMS="(ij_bounds,nk)">
! The tracer array at the appropriate damping time level
! </IN>
! <INOUT NAME="source" TYPE="real" DIMS="(ij_bounds,nk)">
! The tracer source from sponges in [tracer * meter/sec].
! This array is assumed to be previously initialized to 0, and may be
! accumulated through several calls to different subroutines.
! </INOUT>
! <IN NAME="nf" TYPE="integer">
! The tracer number upon which to work
! </IN>
! <IN NAME="time" TYPE="(time_type)">
! The time at which the sponges are being applied
! </IN>
! <IN NAME="dt_in" TYPE="real">
! The time step in seconds
! </IN>
subroutine sponge_tracer_source(t, source, nf, time, dt_in)

  use mpp_mod, only: stdout, stdlog
  use ocean_grids_mod, only: nk, tmask,dht

  real,intent(in), dimension(ij_bounds,nk) :: t 
  real,intent(inout), dimension(ij_bounds,nk) :: source 
  integer, intent(in) :: nf            
  type(time_type),intent(in) :: time    
  real,intent(in) :: dt_in              
  
  real, dimension(ij_bounds,nk) :: data
  logical :: verbose_flag = .false.
  real,parameter :: missing = -1.0e10
  logical :: used
!
  integer :: k, col
! Sponges currently allowed for temp and salt  
    if (nf > 2) then
      write(stdout(),*)'Sponges only for temp and salt, nf = ',nf
      return
    endif
    data = 0.0
!
! We allow writing even when there are no sponges because of
! problems with the diag_manager
    if (sponge_anywhere(nf)) then
      allocate(sponge_val(num_col(nf),nk))
      call time_interp_external(tracer_sponge(nf)%input_id, model_time, data, verbose 
= verbose_flag)
      if (tracer_sponge(nf)%diag_id > 0) then
            used = send_data(tracer_sponge(nf)%diag_id, &
            data(___,1:nk)*sponge_mask(___,1:nk,nf), &
            model_time,rmask=tmask(___,1:nk))
      endif
      do k=1,nk
        do col=1,num_col(nf)
          sponge_val(col,k) = data(isp(col,nf),jsp(col,nf),k)
        enddo
      enddo    
      do col=1,num_col(nf)
        do k=1,nk
          source(isp(col,nf),jsp(col,nf),k) = source(isp(col,nf),jsp(col,nf),k) &
           + dht(isp(col,nf),jsp(col,nf),k)*damp_coef(col,nf,k)*(sponge_val(col,k) - 
t(isp(col,nf),jsp(col,nf),k))      
        enddo    
      enddo
      deallocate(sponge_val)
    else
      if (tracer_sponge(nf)%diag_id > 0) then 
            used = send_data(tracer_sponge(nf)%diag_id, &
            data(___,1:nk), &
            model_time,rmask=tmask(___,1:nk))
      endif 
    endif               
end subroutine sponge_tracer_source
! </SUBROUTINE> NAME="sponge_tracer_source"


!#######################################################################
! <SUBROUTINE NAME="calculate_damp_coef">
!
! <DESCRIPTION>
!
! This subroutine calculates the damping coefficent {damp_coef =
! (1-exp(-dt/rate))/dt} with appropriate checks to handle the limits of
! huge or small damping rates gracefully.
! </DESCRIPTION>
!
! <IN NAME="dt" UNITS="seconds" TYPE="real">
! The time step in seconds
! </IN>
! <IN NAME="nf" TYPE="integer">
! The number of the field whose damping coefficient is being set
! </IN>

subroutine calculate_damp_coef(dt, nf)

  use ocean_grids_mod, only: nk
  real,intent(in) :: dt      
  integer, intent(in) :: nf  
  real :: inv_dt             ! The inverse of the time step, in s-1.
  integer :: col, kk  
  
  inv_dt = 1.0 / dt
  do col=1,num_col(nf)
    do kk=1,nk
    if (dt*inv_damp(col,nf,kk) > 4.0e-8) then
      if (dt*inv_damp(col,nf,kk) > 37.0) then
        damp_coef(col,nf,kk) = inv_dt
      else
        damp_coef(col,nf,kk) = (1.0 - exp(-dt*inv_damp(col,nf,kk))) * inv_dt
      endif
    else if (dt*inv_damp(col,nf,kk) > 0.0) then
      damp_coef(col,nf,kk) = inv_damp(col,nf,kk)
    else
      damp_coef(col,nf,kk) = 0.0
    endif
   enddo
  enddo
end subroutine calculate_damp_coef
! </SUBROUTINE> NAME="calculate_damp_coef"

end module ocean_sponge_mod

Reply via email to