module map_atmocn_mct 3,9
!---------------------------------------------------------------------
!
! Purpose:
!
! Collect coupling routines for sequential coupling of OCN-ATM.
!
! Author: R. Jacob, M. Vertenstein
!
!---------------------------------------------------------------------
use shr_kind_mod
,only: R8 => SHR_KIND_R8, IN=>SHR_KIND_IN
use shr_sys_mod
use shr_const_mod
use shr_mct_mod
, only: shr_mct_sMatPInitnc
use mct_mod
use seq_comm_mct
, only : logunit, loglevel
use seq_cdata_mod
use seq_flds_indices
use seq_infodata_mod
use m_die
implicit none
save
private ! except
!--------------------------------------------------------------------------
! Public interfaces
!--------------------------------------------------------------------------
public :: map_ocn2atm_init_mct
public :: map_atm2ocn_init_mct
public :: map_ocn2atm_mct
public :: map_atm2ocn_mct
!--------------------------------------------------------------------------
! Public data
!--------------------------------------------------------------------------
!--------------------------------------------------------------------------
! Private data
!--------------------------------------------------------------------------
type(mct_rearr), private :: Re_ocn2atm
type(mct_rearr), private :: Re_atm2ocn
type(mct_sMatp), private :: sMatp_Fa2o
type(mct_sMatp), private :: sMatp_Sa2o
type(mct_sMatp), private :: sMatp_Fo2a
type(mct_sMatp), private :: sMatp_So2a
#ifdef CPP_VECTOR
logical :: usevector = .true.
#else
logical :: usevector = .false.
#endif
#ifdef SYSUNICOS
logical :: usealltoall = .true.
#else
logical :: usealltoall = .false.
#endif
logical, private :: samegrid_mapa2o
integer :: ni_a ! number of longitudes on input grid
integer :: nj_a ! number of latitudes on input grid
integer :: ni_o ! number of longitudes on output grid
integer :: nj_o ! number of latitudes on output grid
!=======================================================================
contains
!=======================================================================
subroutine map_atm2ocn_init_mct( cdata_a, cdata_o) 1,6
!-----------------------------------------------------
!
! Arguments
!
type(seq_cdata),intent(in) :: cdata_a
type(seq_cdata),intent(in) :: cdata_o
!
! Local Variables
!
integer :: ka, km ! indices
integer :: lsize ! size of attribute vector
type(seq_infodata_type), pointer :: infodata
type(mct_gsMap), pointer :: gsMap_a
type(mct_gsMap), pointer :: gsMap_o
type(mct_ggrid), pointer :: dom_a
type(mct_ggrid), pointer :: dom_o
type(mct_aVect) :: areasrc ! ocn areas from mapping file
type(mct_aVect) :: areadst ! atm areas from mapping file
integer :: mpicom
character(*),parameter :: subName = '(map_atm2ocn_init_mct) '
!-----------------------------------------------------
call seq_cdata_setptrs
(cdata_a, gsMap=gsMap_a, dom=dom_a)
call seq_cdata_setptrs
(cdata_o, gsMap=gsMap_o, dom=dom_o)
call seq_cdata_setptrs
(cdata_a, mpicom=mpicom, infodata=infodata)
call seq_infodata_GetData
( infodata, samegrid_ao=samegrid_mapa2o)
if (samegrid_mapa2o) then
call mct_rearr_init(gsMap_a, gsMap_o, mpicom, Re_atm2ocn)
!--- want to copy atm area into atm and ocn aream ---
lsize = mct_gsMap_lsize(gsMap_a, mpicom)
call mct_aVect_init( areasrc, rList="aream", lsize=lsize )
lsize = mct_gsMap_lsize(gsMap_o, mpicom)
call mct_aVect_init( areadst, rList="aream", lsize=lsize )
ka = mct_aVect_indexRa(dom_a%data, "area" )
km = mct_aVect_indexRA(areasrc , "aream")
areasrc%rAttr(km,:) = dom_a%data%rAttr(ka,:)
call mct_rearr_rearrange(areasrc, areadst, Re_atm2ocn, VECTOR=usevector, &
ALLTOALL=usealltoall)
ka = mct_aVect_indexRA(areasrc ,"aream")
km = mct_aVect_indexRA(dom_a%data,"aream")
dom_a%data%rAttr(km,:) = areasrc%rAttr(ka,:)
ka = mct_aVect_indexRA(areadst ,"aream")
km = mct_aVect_indexRA(dom_o%data,"aream")
dom_o%data%rAttr(km,:) = areadst%rAttr(ka,:)
call mct_aVect_clean(areasrc)
call mct_aVect_clean(areadst)
else
call shr_mct_sMatPInitnc
(sMatp_Fa2o,gsMap_a,gsMap_o,"seq_maps.rc", &
"atm2ocnFmapname:","atm2ocnFmaptype:",mpicom,&
ni_i=ni_a,nj_i=nj_a,ni_o=ni_o,nj_o=nj_o)
call shr_mct_sMatPInitnc
(sMatp_Sa2o,gsMap_a,gsMap_o,"seq_maps.rc", &
"atm2ocnSmapname:","atm2ocnSmaptype:",mpicom)
endif
end subroutine map_atm2ocn_init_mct
!=======================================================================
subroutine map_ocn2atm_init_mct( cdata_o, cdata_a) 1,6
!-----------------------------------------------------
!
! Arguments
!
type(seq_cdata),intent(in) :: cdata_o
type(seq_cdata),intent(in) :: cdata_a
!
! Local Variables
!
type(seq_infodata_type), pointer :: infodata
integer :: ka, km ! indices
type(mct_gsMap), pointer :: gsMap_o ! ocn gsMap
type(mct_gsMap), pointer :: gsMap_a ! atm gsMap
type(mct_ggrid), pointer :: dom_o ! ocn domain
type(mct_ggrid), pointer :: dom_a ! atm domain
integer :: mpicom ! communicator spanning atm and ocn
integer :: lsize ! size of attribute vector
type(mct_aVect) :: areasrc ! ocn areas from mapping file
type(mct_aVect) :: areadst ! atm areas from mapping file
character(*),parameter :: subName = '(map_ocn2atm_init_mct) '
!-----------------------------------------------------
call seq_cdata_setptrs
(cdata_o, gsMap=gsMap_o, dom=dom_o)
call seq_cdata_setptrs
(cdata_a, gsMap=gsMap_a, dom=dom_a)
call seq_cdata_setptrs
(cdata_o, mpicom=mpicom, infodata=infodata)
call seq_infodata_GetData
( infodata, samegrid_ao=samegrid_mapa2o)
! Initialize ocn->atm mapping or rearranging
if (samegrid_mapa2o) then
call mct_rearr_init(gsMap_o, gsMap_a, mpicom, Re_ocn2atm)
else
lsize = mct_gsMap_lsize(gsMap_o, mpicom)
call mct_aVect_init( areasrc, rList="aream", lsize=lsize )
lsize = mct_gsMap_lsize(gsMap_a, mpicom)
call mct_aVect_init( areadst, rList="aream", lsize=lsize )
call shr_mct_sMatPInitnc
(sMatp_Fo2a, gsMap_o, gsMap_a, "seq_maps.rc", &
"ocn2atmFmapname:", "ocn2atmFmaptype:", mpicom, &
areasrc=areasrc, areadst=areadst)
call shr_mct_sMatPInitnc
(sMatp_So2a, gsMap_o, gsMap_a, "seq_maps.rc", &
"ocn2atmSmapname:", "ocn2atmSmaptype:", mpicom)
!--- copy aream from mapping files
km = mct_aVect_indexRA(dom_o%data,"aream")
ka = mct_aVect_indexRA(areasrc ,"aream")
dom_o%data%rAttr(km,:) = areasrc%rAttr(ka,:)
km = mct_aVect_indexRA(dom_a%data,"aream")
ka = mct_aVect_indexRA(areadst ,"aream")
dom_a%data%rAttr(km,:) = areadst%rAttr(ka,:)
call mct_aVect_clean(areasrc)
call mct_aVect_clean(areadst)
endif
end subroutine map_ocn2atm_init_mct
!=======================================================================
subroutine map_atm2ocn_mct( cdata_a, av_a, cdata_o, av_o, & 3,8
fluxlist, statelist)
!-----------------------------------------------------
!
! Arguments
!
type(seq_cdata) ,intent(in) :: cdata_a
type(mct_aVect) ,intent(in) :: av_a
type(seq_cdata) ,intent(in) :: cdata_o
type(mct_aVect) ,intent(out) :: av_o
character(len=*),intent(in),optional :: fluxlist
character(len=*),intent(in),optional :: statelist
!
! Local Variables
!
type(seq_infodata_type), pointer :: infodata
type(mct_ggrid), pointer :: dom_o
type(mct_ggrid), pointer :: dom_a
type(mct_gsMap), pointer :: gsmap_a
integer :: mpicom
integer :: lsize
integer :: ku,kv
type(mct_aVect) :: av_o_f ! temporary flux attribute vector
type(mct_aVect) :: av_o_s ! temporary state attribute vector
logical :: do_npfix ! npfix on or off
character(*),parameter :: subName = '(map_atm2ocn_mct) '
!-----------------------------------------------------
call seq_cdata_setptrs
(cdata_o, infodata=infodata)
call seq_infodata_GetData
( infodata, npfix=do_npfix)
if (samegrid_mapa2o) then
if (present(fluxlist) .or. present(statelist)) then
if (present(fluxlist)) then
call mct_rearr_rearrange_fldlist
(av_a, av_o, Re_atm2ocn, VECTOR=usevector, &
ALLTOALL=usealltoall, fldlist=fluxlist)
endif
if (present(statelist)) then
call mct_rearr_rearrange_fldlist
(av_a, av_o, Re_atm2ocn, VECTOR=usevector, &
ALLTOALL=usealltoall, fldlist=statelist)
endif
else
call mct_rearr_rearrange(av_a, av_o, Re_atm2ocn, VECTOR=usevector, ALLTOALL=usealltoall)
endif
else
if (present(fluxlist) .or. present(statelist)) then
if (present(fluxlist)) then
lsize = mct_aVect_lsize(av_o)
call mct_aVect_init (av_o_f, rlist=fluxlist , lsize=lsize)
call mct_sMat_avMult(av_a, sMatp_Fa2o, av_o_f, VECTOR=usevector, rList=fluxlist)
call mct_aVect_copy (aVin=av_o_f, aVout=av_o, vector=usevector)
call mct_aVect_clean(av_o_f)
end if
if (present(statelist)) then
lsize = mct_aVect_lsize(av_o)
call mct_aVect_init (av_o_s, rlist=statelist, lsize=lsize)
call mct_sMat_avMult(av_a, sMatp_Sa2o, av_o_s, VECTOR=usevector, rList=statelist)
call mct_aVect_copy (aVin=av_o_s, aVout=av_o, vector=usevector)
call mct_aVect_clean(av_o_s)
end if
else
!--- default is flux mapping
call mct_sMat_avMult(av_a, sMatp_Fa2o, av_o, VECTOR=usevector)
endif
! Correct a->o vector mapping near NP if appropriate
if (do_npfix) then
if (present(statelist)) then
ku = mct_aVect_indexRA(av_a, 'Sa_u', perrwith='quiet')
kv = mct_aVect_indexRA(av_a, 'Sa_v', perrwith='quiet')
if (ku /= 0 .and. kv /= 0) then
call seq_cdata_setptrs
(cdata_o, dom=dom_o)
call seq_cdata_setptrs
(cdata_a, dom=dom_a, gsmap=gsmap_a)
call seq_cdata_setptrs
(cdata_a, mpicom=mpicom)
call map_npfixNew4R
(av_a, av_o, 'Sa_u', 'Sa_v', gsmap_a, dom_a, dom_o, ni_a, nj_a, mpicom)
end if
end if
end if
endif
end subroutine map_atm2ocn_mct
!=======================================================================
subroutine map_ocn2atm_mct( cdata_o, av_o, cdata_a, av_a, & 8,2
fractions_o, fractions_a, &
fluxlist, statelist )
!-----------------------------------------------------
!
! Arguments
!
type(seq_cdata) , intent(in) :: cdata_o
type(mct_aVect) , intent(in) :: av_o
type(seq_cdata) , intent(in) :: cdata_a
type(mct_aVect) , intent(out) :: av_a
type(mct_aVect) , intent(in), optional :: fractions_o
type(mct_aVect) , intent(in), optional :: fractions_a
character(len=*), intent(in), optional :: fluxlist
character(len=*), intent(in), optional :: statelist
!
! Local variables
!
type(mct_aVect) :: temp
type(mct_aVect) :: av_a_f, av_a_s
integer :: ka, ko, kSo_t
integer :: numats,i,j,ier
integer :: lsize
real(R8),allocatable :: recip(:)
integer :: rcnt
real(R8) :: rmax,rsum,rval
character(*),parameter :: subName = '(map_ocn2atm_mct) '
!-----------------------------------------------------
if (samegrid_mapa2o) then
if (present(fluxlist) .or. present(statelist)) then
if (present(fluxlist)) then
call mct_rearr_rearrange_fldlist
(av_o, av_a, Re_ocn2atm, VECTOR=usevector, &
ALLTOALL=usealltoall, fldlist=fluxlist)
end if
if (present(statelist)) then
call mct_rearr_rearrange_fldlist
(av_o, av_a, Re_ocn2atm, VECTOR=usevector, &
ALLTOALL=usealltoall, fldlist=statelist)
end if
else
call mct_rearr_rearrange(av_o, av_a, Re_ocn2atm, VECTOR=usevector, ALLTOALL=usealltoall)
endif
else
! Normalize input data with fraction of atmosphere on ocean grid
if (present(fractions_o) .and. present(fractions_a)) then
lsize = mct_aVect_lsize(av_o)
numats = mct_aVect_nRAttr(av_o)
ko = mct_aVect_indexRA(fractions_o,"ofrac")
call mct_aVect_init(temp, av_o, lsize=lsize)
do j=1,lsize
do i=1,numats
temp%rAttr(i,j) = av_o%rAttr(i,j)* fractions_o%rAttr(ko,j)
end do
end do
! Perform remapping
if (present(fluxlist) .or. present(statelist)) then
if (present (fluxlist)) then
lsize = mct_aVect_lsize(av_a)
call mct_aVect_init (av_a_f, rlist=fluxlist , lsize=lsize)
call mct_sMat_avMult(temp, sMatp_Fo2a, av_a_f, VECTOR=usevector, rList=fluxlist )
call mct_aVect_copy (aVin=av_a_f, aVout=av_a, vector=usevector)
call mct_aVect_clean(av_a_f)
end if
if (present(statelist)) then
lsize = mct_aVect_lsize(av_a)
call mct_aVect_init (av_a_s, rlist=statelist, lsize=lsize)
call mct_sMat_avMult(temp, sMatp_So2a, av_a_s, VECTOR=usevector, rList=statelist)
call mct_aVect_copy (aVin=av_a_s, aVout=av_a, vector=usevector)
call mct_aVect_clean(av_a_s)
end if
else
! --- default is flux mapping
call mct_sMat_avMult(temp, sMatp_Fo2a, av_a_f, VECTOR=usevector)
endif
! Clean up temporary vector
call mct_aVect_clean(temp)
! Denormalize output data with fraction of ocean on atmosphere grid
lsize = mct_aVect_lsize(av_a)
numats = mct_aVect_nRAttr(av_a)
allocate(recip(lsize),stat=ier)
if(ier/=0) call die(subName,'allocate recip',ier)
ko = mct_aVect_indexRA(fractions_a, "ofrac")
do j=1,lsize
recip(j) = 0.0_R8
if (fractions_a%rAttr(ko,j) /= 0.0_R8) then
recip(j)= 1.0_R8 / fractions_a%rAttr(ko,j)
end if
do i =1,numats
av_a%rAttr(i,j) = av_a%rAttr(i,j) * recip(j)
end do
end do
deallocate(recip,stat=ier)
if(ier/=0) call die(subName,'deallocate recip',ier)
else
if (present(fluxlist) .or. present(statelist)) then
if (present (fluxlist)) then
lsize = mct_aVect_lsize(av_a)
call mct_aVect_init (av_a_f, rlist=fluxlist , lsize=lsize)
call mct_sMat_avMult(av_o, sMatp_Fo2a, av_a_f, VECTOR=usevector, rList=fluxlist )
call mct_aVect_copy (aVin=av_a_f, aVout=av_a, vector=usevector)
call mct_aVect_clean(av_a_f)
end if
if (present(statelist)) then
lsize = mct_aVect_lsize(av_a)
call mct_aVect_init (av_a_s, rlist=statelist, lsize=lsize)
call mct_sMat_avMult(av_o, sMatp_So2a, av_a_s, VECTOR=usevector, rList=statelist)
call mct_aVect_copy (aVin=av_a_s, aVout=av_a, vector=usevector)
call mct_aVect_clean(av_a_s)
end if
else
! --- default is flux mapping
call mct_sMat_avMult(av_o, sMatp_Fo2a, av_a, VECTOR=usevector)
endif
end if
end if
end subroutine map_ocn2atm_mct
!=======================================================================
subroutine map_npFixNew4R(buni,buno,fld1,fld2,gsmapi,domi,domo,ni_i,nj_i,mpicom) 1,6
!===============================================================================
! Correct the north pole mapping of velocity fields from the atm to ocn
! grids. This assumes the input grid is a regular lat/lon with the north
! pole surrounded by the last latitude line in the input array. The
! longitudes in the last latitude must be ordered and equally spaced.
!
! 4R is a low memory version of 3R.
! This version (New4R) is the same as 3R except it uses a lot less memory
! and is a bit faster. Like 3R, it saves data between calls and so
! assumes the input grid remains constant for all calls. This is bfb
! with 3R on bluevista as of 2/15/07.
!
! !REVISION HISTORY:
! 2007-Feb-12 - T. Craig -- modified New3R to reduce memory
! 2007-Apr-27 - M. Vertenstein - implemented in sequential system
!===============================================================================
#include <mpif.h>
!
! Arguments
!
type(mct_Avect),intent(in) :: buni ! input attribute vec
type(mct_Avect),intent(out) :: buno ! output attribute vec
character(*) ,intent(in) :: fld1 ! name of first input field
character(*) ,intent(in) :: fld2 ! name of second input field
integer ,intent(in) :: ni_i ! number of longitudes in input grid
integer ,intent(in) :: nj_i ! number of latitudes in input grid
type(mct_gsMap),pointer :: gsmapi ! input gsmap
type(mct_gGrid),pointer :: domi ! input domain
type(mct_gGrid),pointer :: domo ! output domain
integer ,intent(in) :: mpicom ! mpi communicator group
!
! Local Variables
!
integer(IN) :: n,m ! generic indices
integer(IN) :: n1,n2,n3 ! generic indices
integer(IN) :: kui,kvi ! field indices
integer(IN) :: kuo,kvo ! field indices
integer(IN) :: kin ! index index
integer(IN) :: nmin,nmax ! indices of highest latitude in input
integer(IN) :: npts ! local number of points in an aV
integer(IN) :: num ! number of points at highest latitude
integer(IN) :: kloni ! longitude index on input domain
integer(IN) :: klati ! latitude index on input domain
integer(IN) :: klono ! longitude index on output domain
integer(IN) :: klato ! latitude index on output domain
integer(IN) :: index ! index value
real(R8) :: rindex ! index value
real(R8) :: latmax ! value of highest latitude
real(R8) :: olon,olat ! output bundle lon/lat
real(R8) :: ilon,ilat ! input bundle lon/lat
real(R8) :: npu,npv ! np velocity fields relative to lon
real(R8) :: theta1,theta2 ! angles for trig functions
real(R8),allocatable,save :: ilon1(:) ! lon of input grid at highest latitude
real(R8),allocatable,save :: ilat1(:) ! lat of input grid at highest latitude
real(R8),allocatable,save :: ilon2(:) ! lon of input grid at highest latitude
real(R8),allocatable,save :: ilat2(:) ! lat of input grid at highest latitude
real(R8),allocatable :: rarray(:) ! temporary array
real(R8),allocatable :: rarray2(:,:) ! temporary array
real(R8) :: w1,w2,w3,w4 ! weights
real(R8) :: f1,f2,f3,f4 ! function values
real(R8) :: alpha,beta ! used to generate weights
real(R8) :: rtmp ! real temporary
real(R8),allocatable :: lData(:,:) ! last lat local input bundle data
! also compressed global data
real(R8) ,allocatable,save :: alphafound(:) ! list of found alphas
real(R8) ,allocatable,save :: betafound(:) ! list of found betas
integer(IN),allocatable,save :: mfound(:) ! list of found ms
integer(IN),allocatable,save :: nfound(:) ! list of found ns
real(R8) ,allocatable :: rfound(:) ! temporary for copy
integer(IN),allocatable :: ifound(:) ! temporary for copy
integer(IN),save :: cntfound ! number found
integer(IN),save :: cntf_tot ! cntfound total
integer(IN) :: cnt ! loop counter
logical :: found ! search for new interpolation
integer(IN) :: rcode ! error code
integer(IN) :: np1 ! n+1 or tmp
real(R8) :: ilon1x ! tmp
integer(IN),pointer,save :: gindex(:) ! global index
logical,save :: first_call = .true. ! flags 1st invocation of routine
integer(IN),save :: tnpf1,tnpf2,tnpf3,tnpf4,tnpf5,tnpf6,tnpf7,tnpf8,tnpf9
real(R8),parameter :: shr_const_deg2rad = shr_const_pi/180.0_R8 ! deg to rads
integer(IN) :: mype
!--- formats ---
character(*),parameter :: subName = '(map_npFixNew4R) '
character(*),parameter :: F00 = "('(map_npFixNew4R) ',8a)"
character(*),parameter :: F01 = "('(map_npFixNew4R) ',a,i12)"
!-------------------------------------------------------------------------------
call MPI_COMM_RANK(mpicom,mype,rcode)
kui = mct_aVect_indexRA(buni,fld1,perrWith=subName)
kvi = mct_aVect_indexRA(buni,fld2,perrWith=subName)
kuo = mct_aVect_indexRA(buno,fld1,perrWith=subName)
kvo = mct_aVect_indexRA(buno,fld2,perrWith=subName)
! tcx 3/19/08, don't use GlobGridNum, it's not set properly in models
! kin = mct_aVect_indexIA(domi%data,"GlobGridNum",perrWith=subName)
klati = mct_aVect_indexRA(domi%data,"lat" ,perrWith=subName)
kloni = mct_aVect_indexRA(domi%data,"lon" ,perrWith=subName)
klato = mct_aVect_indexRA(domo%data,"lat" ,perrWith=subName)
klono = mct_aVect_indexRA(domo%data,"lon" ,perrWith=subName)
! ni_i, nj_i should be read in from mapping file
nmin = (ni_i)*(nj_i-1) + 1
nmax = ni_i*nj_i
num = ni_i
!---------------------------------------------------------------------------
! Initialization only
!---------------------------------------------------------------------------
if (first_call) then
if (loglevel > 0) write(logunit,F00) " compute bilinear weights & indicies for NP region."
allocate(ilon1(num))
allocate(ilon2(num))
allocate(ilat1(num))
allocate(ilat2(num))
ilon1 = 0._r8
ilon2 = 0._r8
ilat1 = 0._r8
ilat2 = 0._r8
npts = mct_aVect_lSize(domi%data)
call mct_gsMap_orderedPoints(gsMapi, mype, gindex)
do m=1,npts
if (gindex(m).ge.nmin) then ! are on highest latitude
n = gindex(m) - nmin + 1 ! n is 1->ni_i lon index on highest latitude
rtmp = domi%data%rAttr(kloni,m) ! rtmp is longitude value on highest latitude
ilon1(n) = mod(rtmp+360._R8,360._R8) ! ilon1(n) is longitude val mapped from 0->360
ilat1(n) = domi%data%rAttr(klati,m) ! ilat1(n) values should all be the same (i.e. highest lat)
endif
enddo
!--- all gather local data, MPI_SUM is low memory and simple
!--- but is a performance penalty compared to gatherv and copy
!--- or a fancy send/recv
allocate(rarray(num))
rarray = ilat1
call MPI_ALLREDUCE(rarray,ilat1,num,MPI_REAL8,MPI_SUM,mpicom,rcode)
if (rcode.ne.0) then
write(logunit,*) trim(subName),' ilat1 rcode error ',rcode
call shr_sys_abort
()
endif
rarray = ilon1
call MPI_ALLREDUCE(rarray,ilon1,num,MPI_REAL8,MPI_SUM,mpicom,rcode)
if (rcode.ne.0) then
write(logunit,*) trim(subName),' ilon1 rcode error ',rcode
call shr_sys_abort
()
endif
do n = 1,num
np1 = mod(n,num)+1
ilat2(n) = ilat1(np1)
ilon2(n) = ilon1(np1)
if (ilon2(n) < ilon1(n)) ilon2(n) = ilon2(n) + 360._R8
enddo
do n = 1,num
if (ilat1(n) /= ilat2(n)) then
write(logunit,*) trim(subname),' ERROR: ilat1 ne ilat2 ',n,ilat1(n),ilat2(n)
call shr_sys_abort
(trim(subname)//' ERROR: ilat1 ne ilat2')
endif
if (ilon2(n) < ilon1(n)) then
write(logunit,*) trim(subname),' ERROR: ilon2 lt ilon1 ',n,ilon1(n),ilon2(n)
call shr_sys_abort
(trim(subname)//' ERROR: ilon2 ilon1 error')
endif
! tcraig check that lon diffs are reasonable 4x average dlon seems like reasonable limit
if (ilon2(n) - ilon1(n) > (360.0_R8/(num*1.0_R8))*4.0) then
write(logunit,*) trim(subname),' ERROR: ilon1,ilon2 ',n,ilon1(n),ilon2(n)
call shr_sys_abort
(trim(subname)//' ERROR: ilon2 ilon1 size diff')
endif
enddo
latmax = maxval(ilat1)
!--- compute weights and save them ---
npts = mct_aVect_lSize(buno)
allocate(mfound(npts),nfound(npts),alphafound(npts),betafound(npts))
cntfound = 0
do m = 1,npts
olat = domo%data%rAttr(klato,m)
if (olat >= latmax) then
rtmp = domo%data%rAttr(klono,m)
olon = mod(rtmp,360._R8)
n = 1
found = .false.
do while (n <= num .and. .not.found )
if ( olon >= ilon1(n) .and. olon < ilon2(n) .or. &
olon+360._R8 >= ilon1(n) .and. olon < ilon2(n)) then
!tcx ilat2==ilat1 so don't average
!---> ilat = (ilat1(n) + ilat2(n)) * 0.5_R8
ilat = ilat1(n)
if (ilon2(n) == ilon1(n)) then
alpha = 0.5_R8
else if ( olon >= ilon1(n) .and. olon < ilon2(n)) then
alpha = (olon - ilon1(n)) / (ilon2(n) - ilon1(n))
else if (olon+360._R8>= ilon1(n) .and. olon < ilon2(n)) then
alpha = (olon+360._R8 - ilon1(n)) / (ilon2(n) - ilon1(n))
else
write(logunit,*) subName,' ERROR: olon ',olon,ilon1(n),ilon2(n)
endif
if (ilat >= 90._R8) then
beta = 1.0_R8
else
beta = (olat - ilat) / (90._R8 - ilat)
endif
cntfound = cntfound + 1
mfound(cntfound) = m
nfound(cntfound) = n
alphafound(cntfound) = alpha
betafound(cntfound) = beta
found = .true.
endif
n = n + 1 ! normal increment
enddo
if ( .not.found ) then
write(logunit,*) subName,' ERROR: found = false ',found,m,olon,olat
endif
endif
end do
allocate(ifound(npts))
ifound(1:cntfound) = mfound(1:cntfound)
deallocate(mfound)
if (cntfound > 0) then
allocate(mfound(cntfound))
mfound(1:cntfound) = ifound(1:cntfound)
endif
ifound(1:cntfound) = nfound(1:cntfound)
deallocate(nfound)
if (cntfound > 0) then
allocate(nfound(cntfound))
nfound(1:cntfound) = ifound(1:cntfound)
endif
deallocate(ifound)
allocate(rfound(npts))
rfound(1:cntfound) = alphafound(1:cntfound)
deallocate(alphafound)
if (cntfound > 0) then
allocate(alphafound(cntfound))
alphafound(1:cntfound) = rfound(1:cntfound)
endif
rfound(1:cntfound) = betafound(1:cntfound)
deallocate(betafound)
if (cntfound > 0) then
allocate(betafound(cntfound))
betafound(1:cntfound) = rfound(1:cntfound)
endif
deallocate(rfound)
call MPI_ALLREDUCE(cntfound,cntf_tot,1,MPI_INTEGER,MPI_SUM,mpicom,rcode)
if (mype == 0) then
write(logunit,F01) ' total npfix points found = ',cntf_tot
endif
first_call = .false.
endif
!---------------------------------------------------------------------------
! Return if there is nothing to do; must be no points on any pes
! If there are any npfix points, all pes must continue to the np u,v calc
!---------------------------------------------------------------------------
if (cntf_tot < 1) then
return
endif
!---------------------------------------------------------------------------
! Non-initialization, run-time fix
!---------------------------------------------------------------------------
!--- barrier not required but interesting for timing. ---
! call shr_mpi_barrier(mpicom,subName//" barrier")
!--- extract index, u, v from buni ---
allocate(lData(3,num))
lData = 0._R8
npts = mct_aVect_lSize(buni)
do n=1,npts
if (gindex(n).ge.nmin) then
m = gindex(n) - nmin + 1
lData(1,m) = gindex(n)
lData(2,m) = buni%rAttr(kui,n)
lData(3,m) = buni%rAttr(kvi,n)
endif
enddo
!--- all gather local data, MPI_SUM is low memory and simple
!--- but is a performance penalty compared to gatherv and copy
!--- KLUDGE - this should be looked at when it becomes a performance/memory
!--- penalty
allocate(rarray2(3,num))
rarray2=lData
call MPI_ALLREDUCE(rarray2,lData,3*num,MPI_REAL8,MPI_SUM,mpicom,rcode)
deallocate(rarray2)
if (rcode.ne.0) then
write(logunit,*) trim(subName),' rcode error ',rcode
call shr_sys_abort
()
endif
do n2=1,num
if (lData(1,n2).lt.0.1_R8) then
write(logunit,*) trim(subName),' error allreduce ',n2
endif
enddo
!--- compute npu, npv (pole data) and initialize ilon,ilat arrays ---
npu = 0._R8
npv = 0._R8
do n = 1,num
theta1 = ilon1(n)*shr_const_deg2rad
npu = npu + cos(theta1)*lData(2,n) &
- sin(theta1)*lData(3,n)
npv = npv + sin(theta1)*lData(2,n) &
+ cos(theta1)*lData(3,n)
enddo
npu = npu / real(num,R8)
npv = npv / real(num,R8)
!--- compute updated pole vectors ---
!DIR$ CONCURRENT
do cnt = 1,cntfound
m = mfound(cnt)
n = nfound(cnt)
np1 = mod(n,num)+1
alpha = alphafound(cnt)
beta = betafound(cnt)
w1 = (1.0_R8-alpha)*(1.0_R8-beta)
w2 = ( alpha)*(1.0_R8-beta)
w3 = ( alpha)*( beta)
w4 = (1.0_R8-alpha)*( beta)
theta1 = ilon1(n)*shr_const_deg2rad
theta2 = ilon2(n)*shr_const_deg2rad
f1 = lData(2,n)
f2 = lData(2,np1)
f3 = cos(theta1)*npu + sin(theta1)*npv
f4 = cos(theta2)*npu + sin(theta2)*npv
rtmp = w1*f1 + w2*f2 + w3*f3 + w4*f4
buno%rAttr(kuo,m) = w1*f1 + w2*f2 + w3*f3 + w4*f4
f1 = lData(3,n)
f2 = lData(3,np1)
f3 = -sin(theta1)*npu + cos(theta1)*npv
f4 = -sin(theta2)*npu + cos(theta2)*npv
rtmp = w1*f1 + w2*f2 + w3*f3 + w4*f4
buno%rAttr(kvo,m) = w1*f1 + w2*f2 + w3*f3 + w4*f4
enddo
deallocate(lData)
first_call = .false.
end subroutine map_npFixNew4R
!===============================================================================
end module map_atmocn_mct