!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! !!
!! 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 !!
!! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module ocean_riverspread_mod
!
! Mike Spelman
!
!
! S.M. Griffies
!
!
!
! Spread runoff or calving horizontally over a region determined
! by a table.
!
!
!
! At some coastal ocean gridpoints, the runoff or calving flux contribution to
! (p-e+r) may be very large because of local insertion to ocean. Therefore,
! we may choose to spread the large river runoff over neighboring pairs
! of gridpoints. Annual mean river runoff greater than 0.05 m/day is
! considered to be very large.
!
!
!
!
!
! Spreading in a 2D lat-long field is implemented in the following manner:
!
! If the spreading region lives within the halo region
! (i.e., within same local_domain),
! then no added mpp communication required. However, more generally
! the spreading region can extend beyond the existing halo region.
! In this case, spread_domain
! is defined so that its halos incorporate the maximum separation
! of spreading points. New tracer and grid arrays
! are defined over this extended spread_domain. This added domain
! size will come at some computational cost, so it is advantageous
! to choose the spreading region carefully.
!
!
!
! The current implementation of spreading has not been tested
! for a spreading region that is separated by either
! a zonal cyclic condition or across the tripolar fold.
!
!
!
!
!
!
!
! Must be true to enable this module. Default=.false.
!
!
! For debugging. Default=.false.
!
!
!
!
use field_manager_mod, only: MODEL_OCEAN, find_field_index, get_field_methods
use field_manager_mod, only: method_type, get_field_info, parse
use fms_mod, only: write_version_number, open_namelist_file, check_nml_error, close_file
use fms_mod, only: stdout, stdlog, FATAL, NOTE
use mpp_domains_mod, only: domain2D, mpp_update_domains, mpp_define_domains
use mpp_domains_mod, only: cyclic_global_domain, global_data_domain
use mpp_mod, only: mpp_error
use ocean_domains_mod, only: get_local_indices
use ocean_types_mod, only: ocean_domain_type, ocean_grid_type, ocean_options_type
implicit none
private
public ocean_riverspread_init
public spread_river_horz
private on_comp_domain
private on_data_domain
type(ocean_domain_type), pointer :: Dom => NULL()
type(ocean_grid_type), pointer :: Grd => NULL()
! Variables set inside subroutine ocean_riverspread_init
! See comments in ocean_riverspread_init for description
integer, dimension(:), allocatable :: ispread, jspread
integer, dimension(:), allocatable :: is, ie
integer, dimension(:), allocatable :: js, je
integer, dimension(:), allocatable :: halon ! halo size for each spreading region
integer :: nspread=0 ! number of spreading regions
! Variables calculated from user input
integer :: spread_halo ! halo size needed to perform spreading
type(ocean_domain_type), save :: Spread_domain ! domain for spreading
! variables defined with halos given by spread_halo
real, dimension(:,:), allocatable :: field_spreadx !
real, dimension(:,:), allocatable :: xtx ! zonal position of tracer points (degrees)
real, dimension(:,:), allocatable :: ytx ! meridional position of tracer points (degrees)
real, dimension(:,:), allocatable :: datx ! area of tracer cell (m^2)
real, dimension(:,:), allocatable :: tmaskx !
integer :: unit=6 ! processor zero writes to unit 6
logical, dimension(:), allocatable :: error_spread ! for checking that all spread points are OK.
character(len=256) :: version=&
'$Id: ocean_riverspread.F90,v 16.0.70.2.18.1 2009/10/10 00:42:47 nnz Exp $)'
character (len=128) :: tagname = &
'$Name: mom4p1_pubrel_dec2009_nnz $'
integer :: isd, ied, jsd, jed, isc, iec, jsc, jec, nk
logical :: use_this_module = .false.
logical :: debug_this_module = .false.
logical :: module_is_initialized = .FALSE.
namelist /ocean_riverspread_nml/ use_this_module, debug_this_module
contains
!#######################################################################
!
!
!
! Initial set up for spreading of tracers
!
! (i,j) locations of points to be spread are set in data
! statements.
!
! Checks are performed to ensure that the spreading
! grid locations are valid according to model configuration.
!
! A summary of the locations of spreading points is written out.
!
! User specified inputs in "USER INPUT" section:
!
! ispread and jspread = user specified i,j grid locations of data for spreading.
!
! is, ie, js, je = user specified i,j grid locations of
! the corners of the spreading regions.
! is and ie are the east and west coord of each region,
! js and je are the south and north coord of each region.
!
!
!
!
!
! For debugging
!
!
subroutine ocean_riverspread_init(Grid, Domain, Ocean_options)
type(ocean_grid_type), intent(in), target :: Grid
type(ocean_domain_type), intent(in), target :: Domain
type(ocean_options_type), intent(inout) :: Ocean_options
type(method_type), allocatable, dimension(:) :: spread_methods
character(len=32) :: fld_type, fld_name
integer :: i, n, model
integer :: io_status, ioun, ierr
integer :: isp, jsp
integer :: nsp, imax, imin, spread_halo_test
integer :: parse_ok
integer :: stdoutunit,stdlogunit
stdoutunit=stdout();stdlogunit=stdlog()
if ( module_is_initialized ) then
call mpp_error(FATAL, &
'==>Error in ocean_riverspread_mod (ocean_riverspread_init): module already initialized')
endif
module_is_initialized = .TRUE.
call write_version_number( version, tagname )
call get_local_indices(Domain,isd,ied,jsd,jed,isc,iec,jsc,jec)
nk = Grid%nk
Dom => Domain
Grd => Grid
n = find_field_index(MODEL_OCEAN,'riverspread')
if (n < 1) then
write(stdoutunit,*)' '
write(stdoutunit,*) &
'==>Warning: ocean_riverspread_init: n<1 for riverspread table. Will NOT use ocean_riverspread.'
write(stdoutunit,*)' '
Ocean_options%riverspread = 'Did NOT use riverspread module.'
return
endif
! provide for namelist over-ride of default values
ioun = open_namelist_file()
read (ioun,ocean_riverspread_nml,IOSTAT=io_status)
write (stdlogunit,ocean_riverspread_nml)
write (stdoutunit,'(/)')
write (stdoutunit,ocean_riverspread_nml)
ierr = check_nml_error(io_status,'ocean_riverspread_nml')
call close_file (ioun)
call get_field_info(n,fld_type,fld_name,model,nspread)
if(use_this_module) then
call mpp_error(NOTE,&
'==>From ocean_riverspread_mod: Using riverspread module to mix river water into the ocean.')
Ocean_options%riverspread = 'Used riverspread module to horizontally spread river water away from land.'
else
call mpp_error(NOTE,&
'==>From ocean_riverspread_mod: NOT using riverspread module, yet there are n > 0 riverspread points.')
Ocean_options%riverspread = 'Did NOT use riverspread module.'
return
endif
if(nspread == 0) then
call mpp_error(NOTE,&
'==>Warning in ocean_riverspread_mod: No river spreading points chosen.')
Ocean_options%riverspread = 'Did NOT use riverspread module.'
return
endif
if(Grd%tripolar) then
call mpp_error(NOTE,&
'==>Warning in ocean_riverspread_mod: river spreading not implemented for points across bipolar fold.')
endif
allocate(spread_methods(nspread))
allocate (ispread(nspread))
ispread(:) = 0
allocate (jspread(nspread))
jspread(:) = 0
allocate (is(nspread), ie(nspread))
is(:) = 0; ie(:) = 0
allocate (js(nspread), je(nspread))
js(:) = 0; je = 0
allocate (error_spread(nspread))
error_spread(:) = .false.
allocate (halon(nspread))
halon(:) = 0
call get_field_methods(n,spread_methods)
do i=1, nspread
parse_ok = parse(spread_methods(i)%method_control,'iloc',ispread(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "iloc" error')
parse_ok = parse(spread_methods(i)%method_control,'jloc',jspread(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "jloc" error')
parse_ok = parse(spread_methods(i)%method_control,'is',is(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "is" error')
parse_ok = parse(spread_methods(i)%method_control,'ie',ie(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "ie" error')
parse_ok = parse(spread_methods(i)%method_control,'js',js(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "js" error')
parse_ok = parse(spread_methods(i)%method_control,'je',je(i))
if (parse_ok == 0) call mpp_error(FATAL,'==>Error in ocean_riverspread_mod: spread table entry "je" error')
enddo
spread_halo = 1
do nsp=1,nspread
! check for invalid spreading grid locations
if (ispread(nsp) < 1 .or. ispread(nsp) > Grd%ni) then
write(unit,991) nsp, ispread(nsp)
error_spread(nsp) = .true.
endif
if (jspread(nsp) < 1 .or. jspread(nsp) > Grd%nj ) then
write(unit,992) nsp, jspread(nsp)
error_spread(nsp) = .true.
endif
! determine size for spread_halo
if(Grd%cyclic_x) then
imax = max(is(nsp),ie(nsp))
imin = min(is(nsp),ie(nsp))
spread_halo_test = min( abs(imax-imin), abs(imax-Grd%ni-imin))
else
spread_halo_test = abs(is(nsp)-ie(nsp))
endif
if (spread_halo_test > spread_halo ) spread_halo = spread_halo_test
spread_halo_test = abs(js(nsp)-je(nsp))
if (spread_halo_test > spread_halo ) spread_halo = spread_halo_test
halon(nsp) = spread_halo_test
enddo ! end of do-loop nsp=1,nspread
if(spread_halo > Dom%xhalo .or. spread_halo > Dom%yhalo ) then
write(stdoutunit,*)'Defining extra tracer arrays for "riverspread_domain". Halo for spreading = ', spread_halo
write(stdoutunit,*)'Halos for the spreading regions = ', halon
endif
! define arrays and spread_domain
if(spread_halo <=Dom%xhalo .and. spread_halo <= Dom%yhalo) then
write(stdoutunit,*)'Local computational domain is large enough for chosen points in river spreading,'
allocate (datx(isd:ied,jsd:jed))
allocate (xtx(isd:ied,jsd:jed))
allocate (ytx(isd:ied,jsd:jed))
allocate (tmaskx(isd:ied,jsd:jed))
xtx(:,:) = Grd%xt(:,:)
ytx(:,:) = Grd%yt(:,:)
datx(:,:) = Grd%dat(:,:)
tmaskx(:,:) = Grd%tmask(:,:,1)
allocate (field_spreadx(isd:ied,jsd:jed))
field_spreadx(:,:) = 0.0
endif
if(spread_halo > Dom%xhalo .or. spread_halo > Dom%yhalo) then
write(stdoutunit,*)'The model local computational domain has a halo = ',Dom%xhalo, Dom%yhalo
write(stdoutunit,*)'This is smaller than the halo required for river spreading.'
write(stdoutunit,*)'For spreading, will define a new domain type with halo = ', spread_halo
call mpp_define_domains((/1,Grid%ni,1,Grid%nj/),Domain%layout,Spread_domain%domain2d, maskmap=Domain%maskmap,&
xflags = CYCLIC_GLOBAL_DOMAIN, xhalo = spread_halo, yhalo = spread_halo, name='spread',&
x_cyclic_offset = Domain%x_cyclic_offset, y_cyclic_offset = Domain%y_cyclic_offset)
! time independent arrays defined over the spread_domain region
allocate (datx(isc-spread_halo:iec+spread_halo,jsc-spread_halo:jec+spread_halo))
allocate (xtx(isc-spread_halo:iec+spread_halo,jsc-spread_halo:jec+spread_halo))
allocate (ytx(isc-spread_halo:iec+spread_halo,jsc-spread_halo:jec+spread_halo))
allocate (tmaskx(isc-spread_halo:iec+spread_halo,jsc-spread_halo:jec+spread_halo))
datx(:,:) = 0.0
xtx(:,:) = 0.0
ytx(:,:) = 0.0
tmaskx(:,:) = 0.0
datx(isc:iec,jsc:jec) = Grd%dat(isc:iec,jsc:jec)
xtx(isc:iec,jsc:jec) = Grd%xt(isc:iec,jsc:jec)
ytx(isc:iec,jsc:jec) = Grd%yt(isc:iec,jsc:jec)
tmaskx(isc:iec,jsc:jec) = grd%tmask(isc:iec,jsc:jec,1)
call mpp_update_domains (datx(:,:), Spread_domain%domain2d)
call mpp_update_domains (xtx(:,:), Spread_domain%domain2d)
call mpp_update_domains (ytx(:,:), Spread_domain%domain2d)
call mpp_update_domains (tmaskx(:,:), Spread_domain%domain2d)
! time dependent arrays defined over the spread_domain region
allocate (field_spreadx(isc-spread_halo:iec+spread_halo,jsc-spread_halo:jec+spread_halo))
field_spreadx(:,:) = 0.0
endif
do nsp=1,nspread
isp = ispread(nsp)-Dom%ioff
jsp = jspread(nsp)-Dom%joff
! check for attempts to spread land rather than sea
if(on_comp_domain(nsp)) then
if (Grd%kmt(isp,jsp) == 0) then
write (unit,192) ispread(nsp),jspread(nsp),Grd%kmt(isp,jsp)
error_spread(nsp)=.true.
endif
endif
! write out summary information for this spreading point
if(on_comp_domain(nsp)) then
write(unit,191) nsp, ispread(nsp), jspread(nsp) &
,xtx(isp,jsp), ytx(isp,jsp) &
,is(nsp),ie(nsp),js(nsp),je(nsp)
endif
enddo
! bring model down if problems with spreading points
do nsp=1,nspread
if(error_spread(nsp)) then
call mpp_error(FATAL,&
'==>Error in ocean_riverspread_mod: problem in river spread initialization.')
endif
enddo
191 format(/' ===== from ocean_riverspread_init ====='/ &
' for spreading location number',i3,/ &
' spread (i,j) gridpoint (',i4,',',i4,') [long=',f8.3,' lat=',f8.3,']',/ &
' over (is, ie, js, je)= ', 4i6)
192 format(/'=>Error: problem with spreading:',/, &
' land point requested'/ &
' at ispread(',i4,'), jspread(',i4,'),', ' kmt = ',i4,/)
991 format(/'=>Error: problem with spreading:',/, &
' out of bounds i grid location requested'/ &
' ispread(',i4,') was set incorrectly set to = ',i8,/)
992 format(/'=>Error: problem with spreading:',/, &
' out of bounds j-row grid location requested'/ &
' jspread(',i4,') was set incorrectly set to = ',i8,/)
end subroutine ocean_riverspread_init
! NAME="ocean_riverspread_init"
!#######################################################################
!
!
!
! Provide conservative spreading of river runoff field.
!
!
subroutine spread_river_horz (field_spread)
real, intent(inout), dimension(isd:,jsd:) :: field_spread
real :: spread, wtsum
integer :: i, j, nsp
if(nspread == 0) return
if(spread_halo > Dom%xhalo .or. spread_halo > Dom%yhalo) then
field_spreadx(isc:iec,jsc:jec) = field_spread(isc:iec,jsc:jec)
call mpp_update_domains (field_spreadx(:,:), Spread_domain%domain2d)
do nsp=1,nspread
if(at_least_one_in_spread_domain(nsp)) then
if(debug_this_module) then
write(unit,'(a,i3,a,i3,a,8i5)') '=>in spread_river_horz: spreading region= ', nsp, &
' halo= ', halon(nsp), ' region (is, ie, js, je)= ', &
is(nsp),ie(nsp),js(nsp),je(nsp), &
is(nsp)-Dom%ioff, ie(nsp)-Dom%ioff, js(nsp)-Dom%joff, je(nsp)-Dom%joff
endif
spread = 0.0; wtsum = 0.0
do j=js(nsp)-Dom%joff,je(nsp)-Dom%joff
do i=is(nsp)-Dom%ioff,ie(nsp)-Dom%ioff
spread = spread + field_spreadx(i,j) * datx(i,j) * tmaskx(i,j)
wtsum = wtsum + datx(i,j) * tmaskx(i,j)
enddo
enddo
if (wtsum > 0.0) then
spread = spread / wtsum
else
write(unit,'(a,2i6)') '=>ERROR: spreading = 0 at i,j=', ispread(nsp), jspread(nsp)
call mpp_error(FATAL,'==>Error: Problem in spread_river_horz.')
endif
do j=js(nsp)-Dom%joff,je(nsp)-Dom%joff
do i=is(nsp)-Dom%ioff,ie(nsp)-Dom%ioff
field_spreadx(i,j) = spread * tmaskx(i,j)
enddo
enddo
do j=jsc,jec
do i=isc,iec
field_spread(i,j) = field_spreadx(i,j)
enddo
enddo
endif ! end of at_least_one_in_spread_domain(nsp) if-test
enddo ! end of the nspread do-loop
endif ! end of spread_halo > halo if-test
if(spread_halo <= Dom%xhalo .and. spread_halo <= Dom%yhalo) then
do nsp=1,nspread
if(at_least_one_in_spread_domain(nsp)) then
if(debug_this_module) then
write(unit,'(a,i3,a,i3,a,8i5)') '=>in spread_river_horz, compute spreading for region= ', nsp, &
' halo= ', halon(nsp), ' region (is, ie, js, je)= ', &
is(nsp),ie(nsp),js(nsp),je(nsp), &
is(nsp)-Dom%ioff, ie(nsp)-Dom%ioff, js(nsp)-Dom%joff, je(nsp)-Dom%joff
endif
spread = 0.0; wtsum = 0.0
do j=js(nsp)-Dom%joff,je(nsp)-Dom%joff
do i=is(nsp)-Dom%ioff,ie(nsp)-Dom%ioff
spread = spread + field_spread(i,j) * Grd%dat(i,j) * Grd%tmask(i,j,1)
wtsum = wtsum + Grd%dat(i,j) * Grd%tmask(i,j,1)
enddo
enddo
if (wtsum > 0.0) then
spread = spread / wtsum
else
write(unit,'(a,2i6)') '=>ERROR: spreading = 0 at i,j=', ispread(nsp), jspread(nsp)
call mpp_error(FATAL,'==>Error: Problem in spread_river_horz.')
endif
do j=js(nsp)-Dom%joff,je(nsp)-Dom%joff
do i=is(nsp)-Dom%ioff,ie(nsp)-Dom%ioff
field_spread(i,j) = spread *Grd%tmask(i,j,1)
enddo
enddo
endif ! end of at_least_one_in_spread_domain(nsp) if-test
enddo ! end of the nspread do-loop
endif ! end of spread_halo <= halo if-test
end subroutine spread_river_horz
! NAME="spread_river_horz"
!#######################################################################
!
!
!
! Function to see if at least one of the points in the spreading region
! is within the computational domain for the processor.
!
!
!
! Integer labeling the particular spreading region
!
!
function at_least_one_in_spread_domain(nsp)
integer, intent(in) :: nsp
logical :: in_domain, at_least_one_in_spread_domain
if(isc-halon(nsp)+Dom%ioff <= is(nsp) .and. ie(nsp) <= iec+halon(nsp)+Dom%ioff .and. &
jsc-halon(nsp)+Dom%joff <= js(nsp) .and. je(nsp) <= jec+halon(nsp)+Dom%joff) then
in_domain = .true.
else
in_domain = .false.
endif
at_least_one_in_spread_domain = .false.
if(in_domain) at_least_one_in_spread_domain = .true.
end function at_least_one_in_spread_domain
! NAME="at_least_one_in_spread_domain"
!#######################################################################
!
!
!
! Determine if the point is in comp-domain for the processor
!
!
function on_comp_domain(nsp)
integer, intent(in) :: nsp
logical :: on_comp_domain
if(isc+Dom%ioff <= ispread(nsp) .and. ispread(nsp) <= iec+Dom%ioff .and. &
jsc+Dom%joff <= jspread(nsp) .and. jspread(nsp) <= jec+Dom%joff) then
on_comp_domain = .true.
else
on_comp_domain = .false.
endif
end function on_comp_domain
! NAME="on_comp_domain"
!#######################################################################
!
!
!
! Determine if the point is in data-domain for the processor
!
!
function on_data_domain(nsp)
integer, intent(in) :: nsp
logical :: on_data_domain
if(isd+Dom%ioff <= ispread(nsp) .and. ispread(nsp) <= ied+Dom%ioff .and. &
jsd+Dom%joff <= jspread(nsp) .and. jspread(nsp) <= jed+Dom%joff) then
on_data_domain = .true.
else
on_data_domain = .false.
endif
end function on_data_domain
! NAME="on_data_domain"
end module ocean_riverspread_mod