!BOP ===========================================================================
!
! !MODULE: clm_mct_mod -- provides a standard API naming convention for MCT code
!
! !DESCRIPTION:
! This module should be used instead of accessing mct modules directly.
! This module:
! \begin{itemize}
! \item Uses Fortran {\sf use} renaming of MCT routines and data types so that they
! all have an mct\_ prefix and related data types and routines have related names.
! \item Provides easy and uniform access to
! all MCT routines and data types that must be accessed.
! \item Provides a convienient list of
! all MCT routines and data types that can be accessed.
! \item Blocks access to MCT routines that are not used in cpl6.
! \end{itemize}
! This module also includes some MCT-only functions to augment
! the MCT library.
!
! !REVISION HISTORY:
! 2001-Aug-14 - B. Kauffman - first prototype
! 2006-Apr-13 - M. Vertenstein - modified for sequential mode
!
! !INTERFACE: ------------------------------------------------------------------
module clm_mct_mod 7,7
! !USES:
use shr_sys_mod
! share system routines
use shr_mpi_mod
! mpi layer
use shr_const_mod
! constants
use shr_kind_mod
,only: R8 => SHR_KIND_R8
use shr_kind_mod
,only: IN => SHR_KIND_IN
use shr_kind_mod
,only: CL => SHR_KIND_CL
use clm_varctl
,only: iulog
use m_MCTWorld ,only: mct_world_init => init
use m_AttrVect ,only: mct_aVect => AttrVect
use m_AttrVect ,only: mct_aVect_init => init
use m_AttrVect ,only: mct_aVect_clean => clean
use m_AttrVect ,only: mct_aVect_zero => zero
use m_AttrVect ,only: mct_aVect_lsize => lsize
use m_AttrVect ,only: mct_aVect_indexIA => indexIA
use m_AttrVect ,only: mct_aVect_indexRA => indexRA
use m_AttrVect ,only: mct_aVect_getIList => getIList
use m_AttrVect ,only: mct_aVect_getRList => getRList
use m_AttrVect ,only: mct_aVect_expIListToChar => exportIListToChar
use m_AttrVect ,only: mct_aVect_expRListToChar => exportRListToChar
use m_AttrVect ,only: mct_aVect_nIAttr => nIAttr
use m_AttrVect ,only: mct_aVect_nRAttr => nRAttr
use m_AttrVect ,only: mct_aVect_copy => Copy
use m_AttrVect ,only: mct_aVect_exportRattr => exportRattr
use m_AttrVect ,only: mct_aVect_importRattr => importRattr
use m_AttrVect ,only: mct_aVect_exportIattr => exportIattr
use m_AttrVect ,only: mct_aVect_importIattr => importIattr
use m_AttrVectComms ,only: mct_aVect_scatter => scatter
use m_AttrVectComms ,only: mct_aVect_gather => gather
use m_AttrVectComms ,only: mct_aVect_bcast => bcast
use m_GeneralGrid ,only: mct_gGrid => GeneralGrid
use m_GeneralGrid ,only: mct_gGrid_init => init
use m_GeneralGrid ,only: mct_gGrid_clean => clean
use m_GeneralGrid ,only: mct_gGrid_lsize => lsize
use m_GeneralGrid ,only: mct_ggrid_indexIA => indexIA
use m_GeneralGrid ,only: mct_gGrid_indexRA => indexRA
use m_GeneralGrid ,only: mct_gGrid_exportRattr => exportRattr
use m_GeneralGrid ,only: mct_gGrid_importRattr => importRattr
use m_GeneralGrid ,only: mct_gGrid_exportIattr => exportIattr
use m_GeneralGrid ,only: mct_gGrid_importIattr => importIattr
use m_GeneralGridComms ,only: mct_gGrid_scatter => scatter
use m_GeneralGridComms ,only: mct_gGrid_gather => gather
use m_GeneralGridComms ,only: mct_gGrid_bcast => bcast
use m_GlobalSegMap ,only: mct_gsMap => GlobalSegMap
use m_GlobalSegMap ,only: mct_gsMap_init => init
use m_GlobalSegMap ,only: mct_gsMap_clean => clean
use m_GlobalSegMap ,only: mct_gsMap_lsize => lsize
use m_GlobalSegMap ,only: mct_gsMap_gsize => gsize
use m_GlobalSegMap ,only: mct_gsMap_ngseg => ngseg
use m_GlobalSegMap ,only: mct_gsMap_nlseg => nlseg
use m_GlobalSegMap ,only: mct_gsMap_OP => OrderedPoints
use m_GlobalSegMap ,only: mct_gsMap_pelocs => pelocs
use m_Rearranger ,only: mct_rearr => Rearranger
use m_Rearranger ,only: mct_rearr_init => init
use m_Rearranger ,only: mct_rearr_clean => clean
use m_Rearranger ,only: mct_rearr_rearrange => rearrange
use m_SparseMatrixToMaps ,only: mct_sMat_2XgsMap => SparseMatrixToXGlobalSegMap
use m_SparseMatrixToMaps ,only: mct_sMat_2YgsMap => SparseMatrixToYGlobalSegMap
use m_SparseMatrix ,only: mct_sMat => SparseMatrix
use m_SparseMatrix ,only: mct_sMat_Init => init
use m_SparseMatrix ,only: mct_sMat_Vecinit => vecinit
use m_SparseMatrix ,only: mct_sMat_Clean => clean
use m_SparseMatrix ,only: mct_sMat_indexIA => indexIA
use m_SparseMatrix ,only: mct_sMat_indexRA => indexRA
use m_SparseMatrix ,only: mct_sMat_lsize => lsize
use m_SparseMatrix ,only: mct_sMat_nrows => nRows
use m_SparseMatrix ,only: mct_sMat_ncols => nCols
use m_SparseMatrix ,only: mct_sMat_SortPermute => SortPermute
use m_SparseMatrix ,only: mct_sMat_GNumEl => GlobalNumElements
use m_SparseMatrixComms ,only: mct_sMat_ScatterByRow => ScatterByRow
use m_SparseMatrixComms ,only: mct_sMat_ScatterByCol => ScatterByColumn
use m_SparseMatrixPlus ,only: mct_sMatP => SparseMatrixPlus
use m_SparseMatrixPlus ,only: mct_sMatP_init => init
use m_SparseMatrixPlus ,only: mct_sMatP_Vecinit => vecinit
use m_MatAttrVectMul ,only: mct_sMat_avMult => sMatAvMult
use m_GlobalToLocal ,only: mct_sMat_g2lMat => GlobalToLocalMatrix
use m_List ,only: mct_list => list
use m_List ,only: mct_list_init => init
use m_List ,only: mct_list_get => get
use m_List ,only: mct_list_nitem => nitem
use m_List ,only: mct_list_clean => clean
use m_string ,only: mct_string => string
use m_string ,only: mct_string_clean => clean
use m_string ,only: mct_string_toChar => toChar
use m_die ,only: mct_perr_die => mp_perr_die
use m_MergeSorts ,only: mct_indexset => IndexSet
use m_MergeSorts ,only: mct_indexsort => IndexSort
implicit none
!EOP
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
contains
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: mct_aVect_info - print out aVect info for debugging
!
! !DESCRIPTION:
! Print out information about the input MCT {\it AttributeVector}
! {\tt aVect} to stdout. {\tt flag} sets the level of information:
! \begin{enumerate}
! \item print out names of attributes in {\tt aVect}.
! \item also print out local max and min of data in {\tt aVect}.
! \item also print out global max and min of data in {\tt aVect}.
! \item Same as 3 but include name of this routine.
! \end{enumerate}
! If {\tt flag} is 3 or higher, then optional argument {\tt comm}
! must be provided.
! If optional argument {\tt fld} is present, only information for
! that field will be printed.
! If optional argument {\tt istr} is present, it will be output
! before any of the information.
!
!
! !REVISION HISTORY:
! 2003 Jul 01 - B. Kauffman, T. Craig - first version
!
! !INTERFACE: ------------------------------------------------------------------
subroutine mct_aVect_info(flag,aVect,comm,pe,fld,istr),4
! !USES:
! !INPUT/OUTPUT PARAMETERS:
integer(IN) ,intent(in) :: flag ! info level flag
type(mct_aVect),intent(in) :: aVect ! Attribute vector
integer(IN) ,intent(in),optional :: comm ! MPI communicator
integer(IN) ,intent(in),optional :: pe ! processor number
character(*) ,intent(in),optional :: fld ! fld
character(*) ,intent(in),optional :: istr ! string for print
!EOP
!--- local ---
integer(IN) :: i,j,k,n ! generic indicies
integer(IN) :: ks,ke ! start and stop k indices
integer(IN) :: nflds ! number of flds in AV to diagnose
integer(IN) :: nsize ! grid point size of AV
type(mct_string) :: item ! mct string
character(CL) :: itemc ! item converted to char
integer(IN) :: comm_loc ! local variable for comm
integer(IN) :: pe_loc ! local variable for pe
logical :: commOK ! is comm available
logical :: peOK ! is pe available
real(R8),allocatable :: minl(:) ! local min
real(R8),allocatable :: ming(:) ! global min
real(R8),allocatable :: maxl(:) ! local max
real(R8),allocatable :: maxg(:) ! global max
!--- formats ---
character(*),parameter :: subName = '(mct_aVect_info) '
character(*),parameter :: F00 = "('(mct_aVect_info) ',8a)"
character(*),parameter :: F01 = "('(mct_aVect_info) ',a,i9)"
character(*),parameter :: F02 = "('(mct_aVect_info) ',240a)"
character(*),parameter :: F03 = "('(mct_aVect_info) ',a,2es11.3,i4,2x,a)"
!-------------------------------------------------------------------------------
! NOTE: has hard-coded knowledge/assumptions about mct aVect data type internals
!-------------------------------------------------------------------------------
commOK = .false.
peOK = .false.
if (present(pe)) then
peOK = .true.
pe_loc = pe
endif
if (present(comm)) then
commOK = .true.
comm_loc = comm
if (.not.PEOK) then
call shr_mpi_commrank
(comm,pe_loc,subName)
peOK = .true.
endif
endif
nsize = mct_aVect_lsize(aVect)
if (present(fld)) then
nflds = 1
ks = mct_aVect_indexRA(aVect,fld,perrWith=subName)
ke = ks
else
nflds = mct_aVect_nRAttr(aVect)
ks = 1
ke = nflds
endif
if (flag >= 1) then
if (present(istr)) write(iulog,*) trim(istr)
write(iulog,F01) "local size =",nsize
if (associated(aVect%iList%bf)) write(iulog,F02) "iList = ",aVect%iList%bf
if (associated(aVect%rList%bf)) write(iulog,F02) "rList = ",aVect%rList%bf
endif
if (flag >= 2) then
allocate(minl(nflds))
allocate(maxl(nflds))
do k=ks,ke
minl(k) = minval(aVect%rAttr(k,:))
maxl(k) = maxval(aVect%rAttr(k,:))
enddo
if (flag >= 4 .and. commOK) then
allocate(ming(nflds))
allocate(maxg(nflds))
ming = 0._R8
maxg = 0._R8
call shr_mpi_min(minl,ming,comm,subName)
call shr_mpi_max(maxl,maxg,comm,subName)
endif
do k=ks,ke
call mct_aVect_getRList(item,k,aVect)
itemc = mct_string_toChar(item)
call mct_string_clean(item)
write(iulog,F03) 'l min/max ',minl(k),maxl(k),k,trim(itemc)
if (flag >= 3 .and. commOK) then
if ((peOK .and. pe_loc == 0) .or. .not.peOK) then
write(iulog,F03) 'g min/max ',ming(k),maxg(k),k,trim(itemc)
endif
endif
if (flag >= 4 .and. commOK) then
if ((peOK .and. pe_loc == 0) .or. .not.peOK) then
write(iulog,*) trim(subName),'g min/max ',ming(k),maxg(k),k,trim(itemc)
endif
endif
enddo
deallocate(minl)
deallocate(maxl)
if (flag >= 4 .and. commOK) then
deallocate(ming)
deallocate(maxg)
endif
endif
#ifndef UNICOSMP
call shr_sys_flush
(iulog)
#endif
end subroutine mct_aVect_info
!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: mct_aVect_getRAttr - get real F90 array data out of an aVect
!
! !DESCRIPTION:
! Get the data associated with attribute {\tt str} in
! {\it AttributeVector} {\tt aVect} and return in the
! real F90 array data {\tt data}.
! {\tt rcode} will be 0 if succesful, 1 if size of {\tt data}
! does not match size of {\tt aVect} and 2 if {\tt str} is
! not found.
!
! !REMARKS:
! This is like the MCT routine exportRAttr except the output argument
! is not a pointer.
!
! !REVISION HISTORY:
! 2002 Apr xx - B. Kauffman - first version
!
! !INTERFACE: ------------------------------------------------------------------
subroutine mct_aVect_getRAttr(aVect,str,data,rcode) 2
! !INPUT/OUTPUT PARAMETERS:
type(mct_aVect),intent(in) :: aVect ! an Attribute vector
character(*) ,intent(in) :: str ! field name string
real(R8) ,intent(out) :: data(:) ! an F90 array
integer(IN) ,intent(out) :: rcode ! return code
!EOP
!--- local ---
integer(IN) :: k,n,m
integer(IN) :: aVsize
!--- formats ---
character(*),parameter :: subName = "(mct_aVect_getRAttr) "
character(*),parameter :: F00 = "('(mct_aVect_getRAttr) ',8a)"
!-------------------------------------------------------------------------------
!
!-------------------------------------------------------------------------------
rcode = 0
n = mct_aVect_lsize(aVect)
m = size(data)
if (n /= m) then
write(iulog,*) subName,"ERROR: size aV,data,attr = ",n,m,trim(str)
data = SHR_CONST_SPVAL
rcode = 1
return
end if
k = mct_aVect_indexRA(aVect,trim(str) ,perrWith=subName)
if ( k < 1) then
write(iulog,*) subName,"ERROR: attribute not found, var = ",trim(str),", k=",k
data = SHR_CONST_SPVAL
rcode = 2
return
end if
data(:) = aVect%rAttr(k,:)
end subroutine mct_aVect_getRAttr
!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: mct_aVect_putRAttr - put real F90 array data into an aVect
!
! !DESCRIPTION:
! Put the data in array {\tt data} into the {\it AttributeVector}
! {\tt aVect} under the attribute {\tt str}.
! {\tt rcode} will be 0 if succesful, 1 if size of {\tt data}
! does not match size of {\tt aVect} and 2 if {\tt str} is not
! found.
!
! !REMARKS:
! This is like the MCT routine importRAttr except the output argument
! is not a pointer.
! !REVISION HISTORY:
! 2002 Apr xx - B. Kauffman - first version
!
! !INTERFACE: ------------------------------------------------------------------
subroutine mct_aVect_putRAttr(aVect,str,data,rcode)
! !INPUT/OUTPUT PARAMETERS:
type(mct_aVect),intent(out) :: aVect ! Attribute vector
character(*) ,intent(in) :: str
real(R8) ,intent(in) :: data(:)
integer(IN) ,intent(out) :: rcode
!EOP
!--- local ---
integer(IN) :: k,n,m
integer(IN) :: aVsize
!--- formats ---
character(*),parameter :: subName = "(mct_aVect_putRAttr) "
character(*),parameter :: F00 = "('(mct_aVect_putRAttr) ',8a)"
!-------------------------------------------------------------------------------
!
!-------------------------------------------------------------------------------
rcode = 0
n = mct_aVect_lsize(aVect)
m = size(data)
if (n /= m) then
write(iulog,*) subName,"ERROR: size aV,data,attr = ",n,m,trim(str)
rcode = 1
return
end if
k = mct_aVect_indexRA(aVect,trim(str) ,perrWith=subName)
if ( k < 1) then
write(iulog,*) subName,"ERROR: attribute not found, var = ",trim(str),", k=",k
rcode = 2
return
end if
aVect%rAttr(k,:) = data(:)
end subroutine mct_aVect_putRAttr
!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: mct_aVect_accum - accumulate attributes from one aVect to another
!
! !DESCRIPTION:
! This routine accumulates from input argment {\tt aVin} into the output
! {\it AttrVect} argument {\tt aVout} the real and integer attributes specified in
! input {\tt CHARACTER} argument {\tt iList} and {\tt rList}. The attributes can
! be listed in any order. If neither {\tt iList} nor {\tt rList} are provided,
! all attributes shared between {\tt aVin} and {\tt aVout} will be copied.
!
! If any attributes in {\tt aVout} have different names but represent the
! the same quantity and should still be copied, you must provide a translation
! argument {\tt TrList} and/or {\tt TiList}. The translation arguments should
! be identical to the {\tt rList} or {\tt iList} but with the correct {\tt aVout}
! name subsititued at the appropriate place.
!
! {\bf N.B.:} This routine will fail if the {\tt aVout} is not initialized or
! if any of the specified attributes are not present in either {\tt aVout} or {\tt aVin}.
!
! !REVISION HISTORY:
! 2002 Sep 15 - ? - initial version.
!
! !INTERFACE: ------------------------------------------------------------------
subroutine mct_aVect_accum(aVin, rList, TrList, iList, TiList, aVout) 3
! !USES:
use m_die , only : die
use m_stdio , only : stderr
use m_String , only : String_toChar => toChar
use m_String , only : String
use m_String , only : String_init
use m_String , only : String_clean => clean
use m_List , only : List
use m_List, only : List_get => get
use m_List, only : List_nullify => nullify
use m_List, only : List_clean => clean
use m_List, only : init,nitem
use m_AttrVect, only : AttrVect
use m_AttrVect, only : lsize
use m_AttrVect, only : SharedAttrIndexList
implicit none
!INPUT/OUTPUT PARAMETERS
type(AttrVect) ,intent(in) :: aVin
character(*), optional,intent(in) :: iList
character(*), optional,intent(in) :: rList
character(*), optional,intent(in) :: TiList
character(*), optional,intent(in) :: TrList
type(AttrVect) ,intent(inout) :: aVout
!EOP
!--- local ---
type(List) :: rcpList ! The list of real attributes to accum
type(List) :: icpList ! The list of integer attributes to accum
type(List) :: TrcpList ! Names of output attributes corresponding to input
type(List) :: TicpList ! Names of output attributes corresponding to input
type(String) :: attr ! an individual attribute
type(String) :: attr2 ! an individual attribute
integer(IN) :: i,j ! generic indicies
integer(IN) :: rcode ! return code
integer(IN) :: inx,outx
integer(IN) :: num_indices ! Overlapping attribute index number
!--- Overlapping attribute index storage arrays: ---
integer(IN), dimension(:), pointer :: aVinindices, aVoutindices
character(7) :: data_flag ! character variable used as data type flag
!--- formats ---
character(*),parameter :: myname_='mct_accum'
!-------------------------------------------------------------------------------
!
!-------------------------------------------------------------------------------
call List_nullify(rcpList)
call List_nullify(icpList)
call List_nullify(TrcpList)
call List_nullify(TicpList)
if (lsize(aVin) .ne. lsize(aVout)) then
write(stderr,'(2a)')myname_, &
'MCTERROR: Input aV and output aV do not have the same size'
write(stderr,*)myname_, &
'MCTERROR: ',lsize(aVin),lsize(aVout)
call die(myname_,'lsize check',rcode)
endif
!----------------------------------------------------------------------------
! Accum the listed real attributes
!----------------------------------------------------------------------------
if ( present(rList)) then
if( len_trim(rList)>0 ) then
call init(rcpList,rList) ! init.List()
!--- check translation list ---
if ( present(TrList) ) then
if(len_trim(TrList)>0 ) then
call init(TrcpList,TrList)
if ( nitem(rcpList) .ne. nitem(TrcpList)) then
write(stderr,'(2a)')myname_, &
'MCTERROR: Input rList and TrList do not have the same size'
call die(myname_,'nitem TrList check',rcode)
endif
endif
endif
if (nitem(rcpList) .ge. 1) then
do i=1,lsize(aVin)
do j=1,nitem(rcpList)
call List_get(attr,j,rcpList)
if (present(TrList)) then
call List_get(attr2,j,TrcpList)
else
call String_init(attr2,attr)
endif
inx=mct_aVect_indexRA(aVin,String_toChar(attr),dieWith=myname_//'real aVin')
outx=mct_aVect_indexRA(aVout,String_toChar(attr2),dieWith=myname_//'real aVout')
aVout%rAttr(outx,i)=aVout%rAttr(outx,i)+aVin%rAttr(inx,i)
call String_clean(attr)
call String_clean(attr2)
enddo
enddo
endif
call List_clean(rcpList)
if (present(TrList)) call List_clean(TrcpList)
endif
endif
!----------------------------------------------------------------------------
! Accum the listed integer attributes
!----------------------------------------------------------------------------
if ( present(iList) ) then
if (len_trim(iList)>0 ) then
call init(icpList,iList) ! init.List()
!--- check translation list ---
if ( present(TiList) ) then
if (len_trim(TiList)>0 ) then
call init(TicpList,TiList)
if ( nitem(icpList) .ne. nitem(TicpList)) then
write(stderr,'(2a)')myname_, &
'MCTERROR: Input iList and TiList do not have the same size'
call die(myname_,'nitem TiList check',rcode)
endif
endif
endif
if (nitem(icpList) .ge. 1) then
do i=1,lsize(aVin)
do j=1,nitem(icpList)
call List_get(attr,j,icpList)
if (present(TiList)) then
call List_get(attr2,j,TicpList)
else
call String_init(attr2,attr)
endif
inx =mct_aVect_indexIA(aVin ,String_toChar(attr) ,dieWith=myname_//'int aVin')
outx=mct_aVect_indexIA(aVout,String_toChar(attr2),dieWith=myname_//'int aVout')
aVout%iAttr(outx,i)=aVout%iAttr(outx,i)+aVin%iAttr(inx,i)
call String_clean(attr)
call String_clean(attr2)
enddo
enddo
endif
call List_clean(icpList)
if (present(TrList)) call List_clean(TicpList)
endif
endif
!----------------------------------------------------------------------------
! if neither rList nor iList is present, accum shared attibutes from in to out
!----------------------------------------------------------------------------
if ( .not.present(rList) .and. .not.present(iList)) then
data_flag = 'REAL'
call SharedAttrIndexList(aVin, aVout, data_flag, num_indices, &
aVinindices, aVoutindices)
if (num_indices .gt. 0) then
#ifdef CPP_VECTOR
do j=1,num_indices
!CDIR SELECT(VECTOR)
!DIR$ CONCURRENT
do i=1,lsize(aVin)
#else
do i=1,lsize(aVin)
do j=1,num_indices
#endif
aVout%rAttr(aVoutindices(j),i)= &
& aVout%rAttr(aVoutindices(j),i)+aVin%rAttr(aVinindices(j),i)
enddo
enddo
endif
deallocate(aVinindices, aVoutindices,stat=rcode)
if (rcode /= 0) call die(myname_,'deallocate real(Vinindices...',rcode)
data_flag = 'INTEGER'
call SharedAttrIndexList(aVin, aVout, data_flag, num_indices, &
aVinindices, aVoutindices)
if (num_indices .gt. 0) then
#ifdef CPP_VECTOR
do j=1,num_indices
!CDIR SELECT(VECTOR)
!DIR$ CONCURRENT
do i=1,lsize(aVin)
#else
do i=1,lsize(aVin)
do j=1,num_indices
#endif
aVout%iAttr(aVoutindices(j),i)= &
& aVout%iAttr(aVoutindices(j),i)+aVin%iAttr(aVinindices(j),i)
enddo
enddo
endif
deallocate(aVinindices, aVoutindices,stat=rcode)
if (rcode /= 0) call die(myname_,'deallocate int(Vinindices...',rcode)
endif
end subroutine mct_aVect_accum
!===============================================================================
end module clm_mct_mod