#include "wrfcpp.h"
      MODULE atm_coupler_mod
#ifdef WRF_COUPLING
!svn $Id$
!==================================================== John C. Warner ===
!  Copyright (c) 2002-2008 The ROMS/TOMS Group      Hernan G. Arango   !
!   Licensed under a MIT/X style license                               !
!   See License_ROMS.txt                                               !
!=======================================================================
!                                                                      !
!  This module is used to communicate and exchange data between WRF    !
!  other coupled model(s) using the Model Coupling Toolkit (MCT).      !
!                                                                      !
!=======================================================================
!
!  Componenet model registry.
!
      USE m_MCTWorld, ONLY : MCTWorld_init => init
      USE m_MCTWorld, ONLY : MCTWorld_clean => clean
!
!  Domain decompositin descriptor datatype and assocoiated methods.
!
      USE m_GlobalSegMap, ONLY : GlobalSegMap
      USE m_GlobalSegMap, ONLY : GlobalSegMap_init => init
      USE m_GlobalSegMap, ONLY : GlobalSegMap_lsize => lsize
      USE m_GlobalSegMap, ONLY : GlobalSegMap_clean => clean
      USE m_GlobalSegMap, ONLY : GlobalSegMap_Ordpnts => OrderedPoints
!
!  Field storage data types and associated methods.
!
      USE m_AttrVect, ONLY : AttrVect
      USE m_AttrVect, ONLY : AttrVect_init => init
      USE m_AttrVect, ONLY : AttrVect_zero => zero
      USE m_AttrVect, ONLY : AttrVect_clean => clean
      USE m_AttrVect, ONLY : AttrVect_indxR => indexRA
      USE m_AttrVect, ONLY : AttrVect_importRAttr => importRAttr
      USE m_AttrVect, ONLY : AttrVect_exportRAttr => exportRAttr
!
!  Intercomponent communitcations scheduler.
!
      USE m_Router, ONLY : Router
      USE m_Router, ONLY : Router_init => init
      USE m_Router, ONLY : Router_clean => clean
!
!  Intercomponent transfer.
!
      USE m_Transfer, ONLY: MCT_send => send
      USE m_Transfer, ONLY: MCT_recv => recv
      USE m_Transfer, ONLY: MCT_isend => isend
      USE m_Transfer, ONLY: MCT_irecv => irecv
      USE m_Transfer, ONLY: MCT_waitr => waitrecv
      USE m_Transfer, ONLY: MCT_waits => waitsend

# if defined MCT_INTERP_WV2AT || defined MCT_INTERP_OC2AT
!
!  Sparse Matrix DataType and associated methods.
!
      USE m_SparseMatrix, ONLY : SparseMatrix
      USE m_SparseMatrix, ONLY : SparseMatrix_init => init
      USE m_SparseMatrix, ONLY : SparseMatrix_importGRowInd =>          &
     &                           importGlobalRowIndices
      USE m_SparseMatrix, ONLY : SparseMatrix_importGColInd =>          &
     &                           importGlobalColumnIndices
      USE m_SparseMatrix, ONLY : SparseMatrix_importMatrixElts =>       &
     &                           importMatrixElements
      USE m_SparseMatrix, only : SparseMatrix_lsize => lsize
      USE m_SparseMatrix, only : SparseMatrix_GNumElem =>               &
     &                           GlobalNumElements
      USE m_SparseMatrix, only : SparseMatrix_clean => clean
      USE m_SparseMatrixPlus, ONLY : SparseMatrixPlus
      USE m_SparseMatrixPlus, ONLY : SparseMatrixPlus_init => init
      USE m_SparseMatrixPlus, ONLY : SparseMatrixPlus_clean => clean
!
!  Decompose matrix by row.
!
      USE m_SparseMatrixPlus, ONLY : Xonly
!     USE m_SparseMatrixPlus, ONLY : Yonly
!
!  Matrix-Vector multiply methods.
!
      USE m_MatAttrVectMul, ONLY : MCT_MatVecMul => sMatAvMult
# endif
!
      USE mct_wrf_coupler_params
      USE module_parallel
!
      implicit none
!
      PRIVATE

      PUBLIC :: INITIALIZE_ATM_ROUTERS
      PUBLIC :: initialize_atm_coupling
      PUBLIC :: atm_coupling
# ifdef ROMS_COUPLING
      PUBLIC :: atm2ocn_coupling
      PUBLIC :: atmfocn_coupling
      PUBLIC :: atm_coupling_aux4
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      PUBLIC :: atm2wav_coupling
      PUBLIC :: atmfwav_coupling
# endif
      PUBLIC :: finalize_atm_coupling

      include 'mpif.h'
!
!  Declarations.
!

      TYPE T_GlobalSegMap_G
        TYPE(GlobalSegMap) :: GSMapWRF         ! GloabalSegMap variables
      END TYPE T_GlobalSegMap_G
      TYPE (T_GlobalSegMap_G), ALLOCATABLE :: GlobalSegMap_G(:)

!# ifdef MCT_INTERP_WV2AT
!     TYPE T_GSMapInterp_W
!       TYPE(GlobalSegMap) :: GSMapSWAN       ! GloabalSegMap variables
!     END TYPE T_GSMapInterp_W
!     TYPE (T_GSMapInterp_W), ALLOCATABLE :: GSMapInterp_W(:,:)
!# endif
!# ifdef MCT_INTERP_OC2AT
!     TYPE T_GSMapInterp_O
!       TYPE(GlobalSegMap) :: GSMapROMS       ! GloabalSegMap variables
!     END TYPE T_GSMapInterp_O
!     TYPE (T_GSMapInterp_O), ALLOCATABLE :: GSMapInterp_O(:,:)
!# endif
!# if defined MCT_INTERP_OC2AT || defined MCT_INTERP_WV2AT
# ifdef MOVE_NESTS
      TYPE T_GSMapInterp_R
        TYPE(GlobalSegMap) :: GSMapStatic     ! GloabalSegMap variables
      END TYPE T_GSMapInterp_R
      TYPE (T_GSMapInterp_R), ALLOCATABLE :: GSMapInterp_R(:)
# endif

# if defined ROMS_COUPLING
      TYPE T_AttrVect_O
        TYPE(AttrVect) :: atm2ocn_AV            ! AttrVect variables
        TYPE(AttrVect) :: ocn2atm_AV            ! AttrVect variables
      END TYPE T_AttrVect_O
      TYPE (T_AttrVect_O), ALLOCATABLE :: AttrVect_O(:,:)
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      TYPE T_AttrVect_W
       TYPE(AttrVect) :: atm2wav_AV            ! AttrVect variables
       TYPE(AttrVect) :: wav2atm_AV            ! AttrVect variables
      END TYPE T_AttrVect_W
      TYPE (T_AttrVect_W), ALLOCATABLE :: AttrVect_W(:,:)
# endif

# if defined ROMS_COUPLING
      TYPE T_Router_O
        type(Router)   :: WRFtoROMS           ! Router variables
      END TYPE T_Router_O
      TYPE (T_Router_O), ALLOCATABLE :: Router_O(:,:)
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      TYPE T_Router_W
        type(Router)   :: WRFtoSWAN           ! Router variables
      END TYPE T_Router_W
      TYPE (T_Router_W), ALLOCATABLE :: Router_W(:,:)
# endif

!# ifdef MCT_INTERP_WV2AT
!      TYPE T_AV2_W
!        TYPE(AttrVect) :: wav2atm_AV2         ! AttrVect variables
!        TYPE(AttrVect) :: atm2wav_AV2 
!      END TYPE T_AV2_W
!      TYPE (T_AV2_W), ALLOCATABLE :: AV2_W(:,:)

!      TYPE(SparseMatrix) :: sMatA             ! Sparse matrix elements
!      TYPE(SparseMatrix) :: sMatW             ! Sparse matrix elements

!      TYPE T_SMPlus_W
!        TYPE(SparseMatrixPlus) :: W2AMatPlus  ! Sparse matrix plus elements
!        TYPE(SparseMatrixPlus) :: A2WMatPlus  ! Sparse matrix plus elements
!      END TYPE T_SMPlus_W
!      TYPE (T_SMPlus_W), ALLOCATABLE :: SMPlus_W(:,:)
!# endif

!# ifdef MCT_INTERP_OC2AT
!      TYPE T_AV2_O
!        TYPE(AttrVect) :: atm2ocn_AV2           ! AttrVect variables
!        TYPE(AttrVect) :: ocn2atm_AV2
!      END TYPE T_AV2_O
!      TYPE (T_AV2_O), ALLOCATABLE :: AV2_O(:,:)

!#  if !defined MCT_INTERP_WV2AT
!      TYPE(SparseMatrix) :: sMatA             ! Sparse matrix elements
!#  endif
!      TYPE(SparseMatrix) :: sMatO             ! Sparse matrix elements

!      TYPE T_SMPlus_O
!        TYPE(SparseMatrixPlus) :: A2OMatPlus  ! Sparse matrix plus elements
!        TYPE(SparseMatrixPlus) :: O2AMatPlus  ! Sparse matrix plus elements
!      END TYPE T_SMPlus_O
!      TYPE (T_SMPlus_O), ALLOCATABLE :: SMPlus_O(:,:)
!# endif
!# if defined MCT_INTERP_OC2AT || defined MCT_INTERP_WV2AT
# ifdef MOVE_NESTS
      TYPE T_AV2_R
        TYPE(AttrVect) :: crs2fin_AV2         ! AttrVect variables
        TYPE(AttrVect) :: fin2crs_AV2 
      END TYPE T_AV2_R
      TYPE (T_AV2_R), ALLOCATABLE :: AV2_RO(:,:)
      TYPE (T_AV2_R), ALLOCATABLE :: AV2_RW(:,:)

      TYPE(SparseMatrix) :: sMatF             ! Sparse matrix elements
      TYPE(SparseMatrix) :: sMatC             ! Sparse matrix elements

      TYPE T_SMPlus_R
        TYPE(SparseMatrixPlus) :: C2FMatPlus  ! Sparse matrix plus elements
        TYPE(SparseMatrixPlus) :: F2CMatPlus  ! Sparse matrix plus elements
      END TYPE T_SMPlus_R
      TYPE (T_SMPlus_R), ALLOCATABLE :: SMPlus_R(:)
!
!      integer :: par_grid_ratio,full_Isize,full_Jsize,parent_id

# endif

      CONTAINS

      SUBROUTINE initialize_atm_coupling(grid, ia)
!
!=======================================================================
!                                                                      !
!  Initialize waves and ocean models coupling stream.  This is the     !
!  training phase use to constuct  MCT  parallel interpolators and     !
!  stablish communication patterns.                                    !
!                                                                      !
!=======================================================================
!
      USE module_domain

      implicit none
!
!  Imported variable definitions.
!
      TYPE(domain) , INTENT (IN) :: grid 
      integer, intent(in) :: ia

!     include 'mpif.h'
!
!  Local variable declarations.  
!
      integer :: MyError, MyRank
      integer :: npoints, gsmsize, nprocs, localsize
      integer :: j, jc, Isize, Jsize, count, Asize
      integer :: i, is, ie, js, je, cid, cad, io, iw 
      integer :: nRows, nCols, num_sparse_elems

      integer, pointer :: start(:), length(:)
      character (len=120)  :: to_add, avstring

!-----------------------------------------------------------------------
!  Begin initialization phase.
!-----------------------------------------------------------------------
!
!  Get communicator local rank and size.
!
      CALL mpi_comm_rank (ATM_COMM_WORLD, MyRank, MyError)
      CALL mpi_comm_size (ATM_COMM_WORLD, nprocs, MyError)
!
      IF (ia.eq.1) THEN
        ALLOCATE(GlobalSegMap_G(Natm_grids))
# if defined ROMS_COUPLING
        ALLOCATE(AttrVect_O(Natm_grids,Nocn_grids))
!#  ifdef MCT_INTERP_OC2AT
!       ALLOCATE(SMPlus_O(Natm_grids,Nocn_grids))
!       ALLOCATE(AV2_O(Natm_grids,Nocn_grids))
!       ALLOCATE(GSMapInterp_O(Natm_grids,Nocn_grids))
!#  endif
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
        ALLOCATE(AttrVect_W(Natm_grids,Nwav_grids))
!#  ifdef MCT_INTERP_WV2AT
!       ALLOCATE(SMPlus_W(Natm_grids,Nwav_grids))
!       ALLOCATE(AV2_W(Natm_grids,Nwav_grids))
!       ALLOCATE(GSMapInterp_W(Natm_grids,Nwav_grids))
!#  endif
# endif
# ifdef MOVE_NESTS
        ALLOCATE(GSMapInterp_R(Natm_grids))
        ALLOCATE(SMPlus_R(Natm_grids))
        ALLOCATE(AV2_RO(Natm_grids,Nocn_grids))
        ALLOCATE(AV2_RW(Natm_grids,Nwav_grids))
# endif
      END IF
!
!  Initialize MCT coupled model registry.
!
      ATMid=atmids(ia)
      IF (Natm_grids.gt.1) THEN
        CALL MCTWorld_init (N_mctmodels,MPI_COMM_WORLD,                 &
     &                      ATM_COMM_WORLD,myids=atmids)
      ELSE
        CALL MCTWorld_init (N_mctmodels,MPI_COMM_WORLD,                 &
     &                      ATM_COMM_WORLD,ATMid)
      END IF
!
!  Initialize a Global Segment Map for non-haloed transfer of data out
!  of WRF. Determine non-haloed start and length arrays for this
!  processor.
!
      is = grid%sp31
      ie = grid%ep31
      js = grid%sp33
      je = grid%ep33
      IF (grid%ed31.eq.ie) THEN
        ie=ie-1
      END IF
      IF (grid%ed33.eq.je) THEN
        je=je-1
      END IF
!
!  Determine tile size
!
      Isize=ie-is+1
      Jsize=je-js+1
      allocate( start(Jsize) )
      allocate( length(Jsize) )
      jc=0
      DO j=js,je
        jc=jc+1
        start(jc)=(j-1)*(grid%ed31-1)+is
        length(jc)=Isize
      END DO
      gsmsize=Isize*Jsize
!
      CALL GlobalSegMap_init (GlobalSegMap_G(ia)%GSMapWRF,              &
     &                        start, length, 0, ATM_COMM_WORLD, ATMid)
      deallocate(start)
      deallocate(length)
!
# ifdef MOVE_NESTS
!  Save some grid information.
      par_grid_ratio(ia)=grid%parent_grid_ratio
      full_Isize(ia)=grid%e_we-1
      full_Jsize(ia)=grid%e_sn-1
      parent_id(ia)=grid%parent_id
!
      IF ((Myrank.eq.0).and.(moving_nest(ia).eq.1)) THEN
!  For staitc grids, that interpolation occurs in the mct_roms_wrf.h.
!  For moving WRF nests,for now, this will take effect here and
!  we need to interpolate the small moving nest to a defined
!  static larger grid that is the size of
!  parent_grid_ratio . num_cellsx_par . num_cellsy_par
!
!!!!!!!!!!!!!!!!!!!!!!
! First work on atm_moving nest to static grid.
! This really means to interpolate the moving nest to a larger
! static grid that is a factor par_grid_ratio larger.
!!!!!!!!!!!!!!!!!!!!!!
!

          src_grid_dims(1)=full_Isize(ia)
          src_grid_dims(2)=full_Jsize(ia)
          dst_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          dst_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
!
! Init the sparse matrix. Rows = dst grid cell indices (these change).
!                         Cols = src grid cell indices.
!
          num_sparse_elems=src_grid_dims(1)*src_grid_dims(2)
          nRows=dst_grid_dims(1)*dst_grid_dims(2)
          nCols=src_grid_dims(1)*src_grid_dims(2)
!
          allocate ( sparse_rows(num_sparse_elems) )
          allocate ( sparse_cols(num_sparse_elems) )
          allocate ( sparse_weights(num_sparse_elems) )
!
! Create sparse matrix.
!
          DO i=1,num_sparse_elems
            sparse_cols(i)=i
!           sparse_weights(i)=1.0
            sparse_weights(i)=0.0
          END DO

!  Do not use first 3 (or 5) rows around child perimeter.
          jc=0
          DO j=par_grid_ratio(ia)+1,src_grid_dims(2)-par_grid_ratio(ia)
           DO i=par_grid_ratio(ia)+1,src_grid_dims(1)-par_grid_ratio(ia)
              jc=(j-1)*(src_grid_dims(1))+i
              sparse_weights(jc)=1.0
            END DO
          END DO

          is=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          js=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,src_grid_dims(2)
            count=(js-1+j-1)*(dst_grid_dims(1))+is-1
            DO i=1,src_grid_dims(1)
              jc=jc+1
              sparse_rows(jc)=count+i
            END DO
          END DO

          call SparseMatrix_init(sMatF,nRows,nCols,num_sparse_elems)
          call SparseMatrix_importGRowInd(sMatF, sparse_rows,           &
     &                                    num_sparse_elems)
          call SparseMatrix_importGColInd(sMatF, sparse_cols,           &
     &                                    num_sparse_elems)
          call SparseMatrix_importMatrixElts(sMatF, sparse_weights,     &
     &                                    num_sparse_elems)
!
! Deallocate arrays.
!
          deallocate ( sparse_rows )
          deallocate ( sparse_cols )
          deallocate ( sparse_weights )
!
!!!!!!!!!!!!!!!!!!!!!!
! Second work on full static grid to moving nest.
!!!!!!!!!!!!!!!!!!!!!!
!
          dst_grid_dims(1)=full_Isize(ia)
          dst_grid_dims(2)=full_Jsize(ia)
          src_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          src_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
!
! Init the sparse matrix. Rows = dst grid cell indices.
!                         Cols = src grid cell indices (these change).
!
          num_sparse_elems=dst_grid_dims(1)*dst_grid_dims(2)
          nRows=dst_grid_dims(1)*dst_grid_dims(2)
          nCols=src_grid_dims(1)*src_grid_dims(2)
!
          allocate ( sparse_rows(num_sparse_elems) )
          allocate ( sparse_cols(num_sparse_elems) )
          allocate ( sparse_weights(num_sparse_elems) )
!
! Create sparse matrix.
!
          DO i=1,num_sparse_elems
            sparse_rows(i)=i
            sparse_weights(i)=1.0
          END DO
          is=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          js=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,dst_grid_dims(2)
            count=(js-1+j-1)*(src_grid_dims(1))+is-1
            DO i=1,dst_grid_dims(1)
!              count=(js-1)*(src_grid_dims(1))+is+1
              jc=jc+1
              sparse_cols(jc)=count+i
            END DO
          END DO
!
          call SparseMatrix_init(sMatC,nRows,nCols,num_sparse_elems)
          call SparseMatrix_importGRowInd(sMatC, sparse_rows,           &
     &                                    num_sparse_elems)
          call SparseMatrix_importGColInd(sMatC, sparse_cols,           &
     &                                    num_sparse_elems)
          call SparseMatrix_importMatrixElts(sMatC, sparse_weights,     &
     &                                    num_sparse_elems)
!
! Deallocate arrays.
!
          deallocate ( sparse_rows )
          deallocate ( sparse_cols )
          deallocate ( sparse_weights )
        END IF
        IF (moving_nest(ia).eq.1) THEN
!
!  Create Global Seg Map for the static larger grid.
!  Determine start and lengths for domain decomposition.
!
          dst_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          dst_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
          Isize=INT(dst_grid_dims(1)/nprocs)
          IF (MyRank.eq.nprocs-1) THEN
            Isize=dst_grid_dims(1)-Isize*(nprocs-1)
          ENDIF
          allocate( start(1) )
          allocate( length(1) )
          start=(MyRank*INT(dst_grid_dims(1)/nprocs))*dst_grid_dims(2)+1
          length=Isize*dst_grid_dims(2)
!
          CALL GlobalSegMap_init (GSMapInterp_R(ia)%GSMapStatic,        &
     &                            start,length,0,ATM_COMM_WORLD,ATMid)
          deallocate (start)
          deallocate (length)
!
! Create ATM sparse matrix plus for interpolation.
! Specify matrix decomposition to be by row.
!
          call SparseMatrixPlus_init(SMPlus_R(ia)%F2CMatPlus, sMatF,    &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
!         call SparseMatrix_clean(sMatA)
!
! Create Ocean sparse matrix plus for interpolation.
! Specify matrix decomposition to be by row.
!
          call SparseMatrixPlus_init(SMPlus_R(ia)%C2FMatPlus, sMatC,    &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
!         call SparseMatrix_clean(sMatO)
        END IF
# endif
# ifdef ROMS_COUPLING
!
!  Initialize attribute vector holding the export data code strings of
!  the atmosphere model.
      cad=LEN(avstring)
      DO j=1,cad
        avstring(j:j)=''
      END DO
      cid=1
!
      to_add='GSW'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':GLW'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
#  ifdef ATM2OCN_FLUXES
      to_add=':LH'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':HFX'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':USTRESS'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':VSTRESS'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  if defined BULK_FLUXES || defined ECOSIM || defined ATM_PRESS
      to_add=':MSLP'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  if defined BULK_FLUXES || defined ECOSIM || \
   (defined SHORTWAVE && defined ANA_SRFLUX)
      to_add=':RELH'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':T2'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  if defined BULK_FLUXES || defined ECOSIM
      to_add=':U10'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
!
      to_add=':V10'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  ifdef CLOUDS
      to_add=':CLDFRA'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  if !defined ANA_RAIN && defined EMINUSP
      to_add=':RAIN'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
!
#  if defined EMINUSP
      to_add=':EVAP'
      cad=LEN_TRIM(to_add)
      write(avstring(cid:cid+cad-1),'(a)') to_add(1:cad)
      cid=cid+cad
#  endif
      cad=LEN_TRIM(avstring)
      avstring=avstring(1:cad)
!
      DO io=1,Nocn_grids
        OCNid=ocnids(io)
        CALL AttrVect_init (AttrVect_O(ia,io)%atm2ocn_AV,               &
     &                      rlist=TRIM(avstring),lsize=gsmsize)
        CALL AttrVect_zero (AttrVect_O(ia,io)%atm2ocn_AV)
!
!  Initialize attribute vector holding the export data code string of
!  the ocean model.
#  ifdef MCT_INTERP_OC2AT
        CALL AttrVect_init (AttrVect_O(ia,io)%ocn2atm_AV,               &
     &                      rList="SST:CPL_MASK",lsize=gsmsize)
#  else
        CALL AttrVect_init (AttrVect_O(ia,io)%ocn2atm_AV,               &
     &                      rList="SST",lsize=gsmsize)
#  endif
        CALL AttrVect_zero (AttrVect_O(ia,io)%ocn2atm_AV)

#  ifdef MOVE_NESTS
        IF (moving_nest(ia).eq.1) THEN
!
!  Initialize attribute vector holding the export data of
!  the atm model. The Asize is the number of grid point on this
!  processor.
!
          Asize=GlobalSegMap_lsize(GSMapInterp_R(ia)%GSMapStatic,       &
     &                             ATM_COMM_WORLD)
          CALL AttrVect_init (AV2_RO(ia,io)%crs2fin_AV2,                &
     &                        rList="SST:CPL_MASK",lsize=Asize)
          CALL AttrVect_zero (AV2_RO(ia,io)%crs2fin_AV2)
!
!  Initialize attribute vector holding the export data code string of
!  the ocean model.
!
          CALL AttrVect_init (AV2_RO(ia,io)%fin2crs_AV2,                &
     &                        rlist=TRIM(avstring),lsize=Asize)
          CALL AttrVect_zero (AV2_RO(ia,io)%fin2crs_AV2)
        END IF
#  endif
      END DO
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      DO iw=1,Nwav_grids
        WAVid=wavids(iw)
!
!  Initialize attribute vector holding the export data code string of
!  the wave model.
!
        CALL AttrVect_init (AttrVect_W(ia,iw)%atm2wav_AV,               &
     &                      rlist="U10:V10",lsize=gsmsize)
        CALL AttrVect_zero (AttrVect_W(ia,iw)%atm2wav_AV)
!
!  Initialize attribute vector for data from SWAN.
!
#  ifdef MCT_INTERP_WV2AT
        CALL AttrVect_init (AttrVect_W(ia,iw)%wav2atm_AV,               &
     &                      rList="HSIGN:WLENP:RTP:CPL_MASK",           &
     &                      lsize=gsmsize)
#  else
        CALL AttrVect_init (AttrVect_W(ia,iw)%wav2atm_AV,               &
     &                      rList="HSIGN:WLENP:RTP",lsize=gsmsize)
#  endif
        CALL AttrVect_zero (AttrVect_W(ia,iw)%wav2atm_AV)
#  ifdef MOVE_NESTS
        IF (moving_nest(ia).eq.1) THEN
!
!  Initialize attribute vector holding the export data of
!  the atm model. The Asize is the number of grid point on this
!  processor.
!
          Asize=GlobalSegMap_lsize(GSMapInterp_R(ia)%GSMapStatic,       &
     &                             ATM_COMM_WORLD)
          CALL AttrVect_init (AV2_RW(ia,iw)%crs2fin_AV2,                &
     &                        rList="HSIGN:WLENP:RTP:CPL_MASK",         &
     &                        lsize=Asize)
          CALL AttrVect_zero (AV2_RW(ia,iw)%crs2fin_AV2)
!
!  Initialize attribute vector holding the export data code string of
!  the ocean model.
!
          CALL AttrVect_init (AV2_RW(ia,iw)%fin2crs_AV2,                &
     &                        rList="U10:V10",lsize=Asize)
          CALL AttrVect_zero (AV2_RW(ia,iw)%fin2crs_AV2)
        END IF
#  endif
      END DO
# endif

      RETURN
      END SUBROUTINE initialize_atm_coupling

      SUBROUTINE INITIALIZE_ATM_ROUTERS
!
!=======================================================================
!                                                                      !
!  Initialize atm routers.                                             !
!                                                                      !
!=======================================================================

      implicit none
!
!  Local variable declarations.
!
      integer :: io, iw, ia
!
!  Initialize MCT Routers.
!
# ifdef ROMS_COUPLING
      ALLOCATE(Router_O(Natm_grids,Nocn_grids))
!
!  Initialize a router to the ocean model component.
!
      DO io=1,Nocn_grids
        DO ia=1,Natm_grids
          OCNid=ocnids(io)
#  ifdef MOVE_NESTS
          IF (moving_nest(ia).eq.1) THEN
            CALL Router_init (OCNid, GSMapInterp_R(ia)%GSMapStatic,     &
     &                        ATM_COMM_WORLD, Router_O(ia,io)%WRFtoROMS)
          ELSE
#  endif
            CALL Router_init (OCNid, GlobalSegMap_G(ia)%GSMapWRF,       &
     &                        ATM_COMM_WORLD, Router_O(ia,io)%WRFtoROMS)
#  ifdef MOVE_NESTS
          END IF 
#  endif
        END DO
      END DO
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      ALLOCATE(Router_W(Natm_grids,Nwav_grids))
!
!  Initialize a router to the wav model component.
!
      DO ia=1,Natm_grids
        DO iw=1,Nwav_grids
          WAVid=wavids(iw)
#  ifdef MOVE_NESTS
          IF (moving_nest(ia).eq.1) THEN
            CALL Router_init (WAVid, GSMapInterp_R(ia)%GSMapStatic,     &
     &                        ATM_COMM_WORLD, Router_W(ia,iw)%WRFtoSWAN)
          ELSE
#  endif
            CALL Router_init (WAVid, GlobalSegMap_G(ia)%GSMapWRF,       &
     &                        ATM_COMM_WORLD, Router_W(ia,iw)%WRFtoSWAN)
#  ifdef MOVE_NESTS
          END IF
#  endif
        END DO
      END DO
# endif

      RETURN
      END SUBROUTINE INITIALIZE_ATM_ROUTERS

      SUBROUTINE atm_coupling(grid, num_steps)
!
!=======================================================================
!                                                                      !
!  Determine which other model to do the coupling at this time step.   !
!                                                                      !
!=======================================================================
!
      USE module_domain

      implicit none

!
!  Imported variable definitions.
!
      integer, intent(in) :: num_steps
!     TYPE(domain) , INTENT (IN) :: grid
      TYPE(domain) , POINTER     :: grid
      TYPE(domain) , POINTER     :: grid_ptr
!
!  Local variable declarations.  
!
      integer :: io, iw, ia, offset
      integer :: kid, num_ksteps
!
      IF (num_steps.eq.0) THEN
        offset=0
      ELSE
!       offset=-1
        offset=0
      END IF
# ifdef ROMS_COUPLING
      IF (MOD(num_steps+offset, nATM2OCN(1,1)).eq.0) THEN
        DO io=1,Nocn_grids
          ia=1
          CALL atm2ocn_coupling(grid,ia,io)
          DO ia=2,Natm_grids
            CALL find_grid_by_id(ia, grid, grid_ptr)
            CALL atm2ocn_coupling(grid_ptr,ia,io)
          END DO
        END DO
      END IF
!
      IF (MOD(num_steps+offset, nATMFOCN(1,1)).eq.0) THEN
        DO io=1,Nocn_grids
          ia=1
          CALL atmfocn_coupling(grid,ia,io,0)
          DO ia=2,Natm_grids
            CALL find_grid_by_id(ia, grid, grid_ptr)
            CALL atmfocn_coupling(grid_ptr,ia,io,0)
          END DO
        END DO
      END IF
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
      IF (MOD(num_steps+offset, nATM2WAV(1,1)).eq.0) THEN
        DO iw=1,Nwav_grids
          ia=1
          CALL atm2wav_coupling(grid,ia,iw)
          DO ia=2,Natm_grids
            CALL find_grid_by_id(ia, grid, grid_ptr)
            CALL atm2wav_coupling(grid_ptr,ia,iw)
          END DO
        END DO
      END IF
!
      IF (MOD(num_steps+offset, nATMFWAV(1,1)).eq.0) THEN
        DO iw=1,Nwav_grids
          ia=1
          CALL atmfwav_coupling(grid,ia,iw)
          DO ia=2,Natm_grids
            CALL find_grid_by_id(ia, grid, grid_ptr)
            CALL atmfwav_coupling(grid_ptr,ia,iw)
          END DO
        END DO
      END IF
# endif

      RETURN
      END SUBROUTINE atm_coupling

# ifdef ROMS_COUPLING
      SUBROUTINE atm_coupling_aux4(grid, num_steps)
!
!=======================================================================
!                                                                      !
!  Determine which other model to do the coupling at this time step.   !
!                                                                      !
!=======================================================================
!
      USE module_domain

      implicit none
!
!  Imported variable definitions.
!
      integer, intent(in) :: num_steps
      TYPE(domain) , POINTER     :: grid 
      TYPE(domain) , POINTER     :: grid_ptr
!
!  Local variable declarations.  
!
      integer :: io, ia
      integer :: kid, num_ksteps
!
      DO io=1,Nocn_grids
        ia=1
        CALL atmfocn_coupling (grid,ia,io,1)
        DO ia=2,Natm_grids
          CALL find_grid_by_id(ia, grid, grid_ptr)
          CALL atmfocn_coupling(grid_ptr,ia,io,1)
        END DO
      END DO

      RETURN
      END SUBROUTINE atm_coupling_aux4
# endif

# ifdef ROMS_COUPLING
      SUBROUTINE atm2ocn_coupling (grid, ia, io)
!
!=======================================================================
!                                                                      !
!  This subroutine reads and writes the coupled data streams.          !
!  Currently, the following data streams are processed:                !
!                                                                      !
!  Possible fields exported to the OCEAN Model:                        !
!                                                                      !
!     * GSW        Short wave raditaion  (Watts/m2)                    !
!     * GLW        Long wave raditaion  (Watts/m2)                     !
!     * LH         Latent heat flux     (Watts/m2)                     !
!     * HFX        Sensible heat flux   (Watts/m2)                     !
!     * USTRESS    Surface U-wind stress (Pa)                          !
!     * VSTRESS    Surface v-stress      (Pa)                          !
!     * MSLP       Mean Sea Level Pressure (Pa)                        !
!     * RELH       Surface air relative humidity (percent)             !
!     * T2         Surface 2m air temperature (Celsius)                !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!     * CLDFRA     Cloud fraction       (percent/100)                  !
!     * RAIN       Precipitation        (m/s)                          !
!     * EVAP       Evaporation          (m/s)                          !
!                                                                      !
!  Fields exported to the WAVE Model:                                  !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!                                                                      !
!  Fields acquired from the WAVE Model:                                !
!                                                                      !
!     * HISGN      Significant wave heigth (m)                         !
!     * WLENP      Peak wave length (m)                                !
!     * RTP        Peak wave period (s)                                !
!                                                                      !
!  Fields acquired from the OCEAN Model:                               !
!                                                                      !
!     * SST        Sea surface temperature                             !
!=======================================================================
!
      USE module_domain
!
      implicit none
!     TYPE(domain) , INTENT (IN) :: grid
      TYPE(domain) , POINTER     :: grid            ! jcw check this
#  ifdef MOVE_NESTS
      TYPE(domain) , POINTER     :: grid_ptr
#  endif
      integer, intent(in) :: ia, io
!
!  Local variable declarations.
!
      integer :: is, ie, js, je, ij, Tag
      integer :: MyStatus, i, j, Asize, ierr, MyRank
      integer :: MyError, MySize, indx, Istr, Iend, Jstr, Jend
      integer :: Isize, Jsize, nprocs, offset
#  ifdef MOVE_NESTS
      integer :: count, jc, num_sparse_elems
#  endif

      real, parameter :: eps=1.0e-10
      real :: cff, cff1, cff2, cff3, rnum, rden, c04, c05
      real, pointer :: AA(:)
#  ifdef MOVE_NESTS
      real, pointer :: MOV_MASK(:,:)
#  endif
!
!  Set grid range.
!
      is = grid%sp31
      ie = grid%ep31
      js = grid%sp33
      je = grid%ep33
      IF (grid%ed31.eq.ie) THEN
        ie=ie-1
      END IF
      IF (grid%ed33.eq.je) THEN
        je=je-1
      END IF
      Isize=ie-is+1
      Jsize=je-js+1
!
!-----------------------------------------------------------------------
!  Send atmosphere fields to ROMS.
!-----------------------------------------------------------------------
!
      CALL MPI_COMM_RANK (ATM_COMM_WORLD, MyRank, MyError)
      CALL MPI_COMM_SIZE (ATM_COMM_WORLD, nprocs, MyError)
!
!  Get the number of grid point on this processor.
!
      Asize=GlobalSegMap_lsize(GlobalSegMap_G(ia)%GSMapWRF,             &
     &                         ATM_COMM_WORLD)
!
!  Allocate attribute vector array used to export/import data.
!
      allocate ( AA(Asize), stat=ierr )
!
#  ifdef MOVE_NESTS
!  If we have a moving nest, then need to mask out parent location of
!  the child nest.
!
      allocate ( MOV_MASK(is:ie,js:je), stat=ierr )
      DO i=is,ie
        DO j=js,je
          MOV_MASK(i,j)=1.0
        END DO
      END DO
!  Get Istr and Jstr of moving child in parent grid.
!  Allow parent to provide one more row around child perimeter.


!  want to know:
!  1 - do you have a child that is moving?
!  2  - if so, then where is it now?

        IF (ia.eq.parent_id(Natm_grids)) THEN
          CALL find_grid_by_id(Natm_grids, grid, grid_ptr)
          offset=1
          Istr=grid_ptr%i_parent_start+offset
          Jstr=grid_ptr%j_parent_start+offset
          ij=full_Isize(Natm_grids)/par_grid_ratio(Natm_grids)
          Iend=grid_ptr%i_parent_start+ij-1-offset
          ij=full_Jsize(Natm_grids)/par_grid_ratio(Natm_grids)
          Jend=grid_ptr%j_parent_start+ij-1-offset
!
          IF ((Istr.ge.is).or.(Istr.le.ie)) THEN
            IF ((Jstr.ge.js).or.(Jstr.le.je)) THEN
              DO i=MAX(is,Istr),MIN(Iend,ie)
                DO j=MAX(js,Jstr),MIN(Jend,je)
                  MOV_MASK(i,j)=0.0
                END DO
              END DO
            END IF
          END IF
        END IF
!
!  Adjust the sparse matrices here.
!
!       IF (ia.eq.Natm_grids) THEN
        IF ((Myrank.eq.0).and.(moving_nest(ia).eq.1)) THEN

!  First the fine to coarse
          src_grid_dims(1)=full_Isize(ia)
          src_grid_dims(2)=full_Jsize(ia)
          dst_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          dst_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
          num_sparse_elems=src_grid_dims(1)*src_grid_dims(2)
          allocate ( sparse_rows(num_sparse_elems) )
!
          Istr=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          Jstr=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,src_grid_dims(2)
            count=(Jstr-1+j-1)*(dst_grid_dims(1))+Istr-1
            DO i=1,src_grid_dims(1)
              jc=jc+1
              sparse_rows(jc)=count+i
            END DO
          END DO
          call SparseMatrix_importGRowInd(sMatF, sparse_rows,           &
     &                                    num_sparse_elems)
          deallocate ( sparse_rows )
!
! Second the coarse to fine.
!
          dst_grid_dims(1)=full_Isize(ia)
          dst_grid_dims(2)=full_Jsize(ia)
          src_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          src_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
          num_sparse_elems=dst_grid_dims(1)*dst_grid_dims(2)
          allocate ( sparse_cols(num_sparse_elems) )
          Istr=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          Jstr=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,dst_grid_dims(2)
            count=(Jstr-1+j-1)*(src_grid_dims(1))+Istr-1
            DO i=1,dst_grid_dims(1)
              jc=jc+1
              sparse_cols(jc)=count+i
            END DO
          END DO
          call SparseMatrix_importGColInd(sMatC, sparse_cols,           &
     &                                    num_sparse_elems)
          deallocate ( sparse_cols )
        END IF
        IF (moving_nest(ia).eq.1) THEN
!  reinit the matrices
          call SparseMatrixPlus_clean(SMPlus_R(ia)%F2CMatPlus)
          call SparseMatrixPlus_init(SMPlus_R(ia)%F2CMatPlus, sMatF,    &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
!
          call SparseMatrixPlus_clean(SMPlus_R(ia)%C2FMatPlus)
          call SparseMatrixPlus_init(SMPlus_R(ia)%C2FMatPlus, sMatC,    &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
        END IF
#  endif
!
!-----------------------------------------------------------------------
!  Export fields from atmosphere (WRF) to ocean (ROMS) model.
!-----------------------------------------------------------------------
!     GSW        Short wave raditaion (W m-2).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%GSW(i,j)
#  ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#  endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "GSW",   &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     GLW        Long wave raditaion (W m-2).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%GLW(i,j)
#  ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#  endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "GLW",   &
     &                           AA, Asize)
#  ifdef ATM2OCN_FLUXES
!-----------------------------------------------------------------------
!     LH     Latent heat flux (W m-2).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%LH(i,j)
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "LH",    &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     HFX     Sensible heat flux (W m-2).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%HFX(i,j)
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "HFX",   &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     USTRESS    Surface u-stress (m2 s-2).
!     Use Uearth and Vearth rotated velocities to partition UST.
!
      ij=0
      DO j=js,je
        DO i=is,ie
          cff1=1.0/(grid%alt(i,1,j)+eps)
          cff2=2.0/(((grid%u_2(i,1,j)+grid%u_2(i+1,1,j))**2+            &
     &               (grid%v_2(i,1,j)+grid%v_2(i,1,j+1))**2)**0.5+eps)
          ij=ij+1
          cff3=0.5*(grid%u_2(i,1,j)+grid%u_2(i+1,1,j))*grid%cosa(i,j)-  &
     &         0.5*(grid%v_2(i,1,j)+grid%v_2(i,1,j+1))*grid%sina(i,j)
          cff=cff1*cff2*(grid%UST(i,j)**2)*cff3
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV,"USTRESS",&
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     VSTRESS    Surface v-stress (m2 s-2).
!     Use Uearth and Vearth rotated velocities to partition UST.
!
      ij=0
      DO j=js,je
        DO i=is,ie
          cff1=1.0/(grid%alt(i,1,j)+eps)
          cff2=2.0/(((grid%u_2(i,1,j)+grid%u_2(i+1,1,j))**2+            &
     &               (grid%v_2(i,1,j)+grid%v_2(i,1,j+1))**2)**0.5+eps)
          ij=ij+1
          cff3=0.5*(grid%v_2(i,1,j)+grid%v_2(i,1,j+1))*grid%cosa(i,j)+  &
     &         0.5*(grid%u_2(i,1,j)+grid%u_2(i+1,1,j))*grid%sina(i,j)
          cff=cff1*cff2*(grid%UST(i,j)**2)*cff3
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV,"VSTRESS",&
     &                           AA, Asize)
#  endif
#  if defined BULK_FLUXES || defined ECOSIM || defined ATM_PRESS
!-----------------------------------------------------------------------
!     MSLP       Surface atmospheric pressure (Pa).
!     Use the hypsometric equation to reduce 
!     surface pressure to mean sea level pressure.
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%PSFC(i,j)*                                           &
     &           exp((9.81*grid%ht(i,j))/                               &
     &           (287.0*grid%T2(i,j)*(1.0+0.61*grid%Q2(i,j))))
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "MSLP",  &
     &                           AA, Asize)
#  endif
#  if defined BULK_FLUXES || defined ECOSIM || \
     (defined SHORTWAVE && defined ANA_SRFLUX)
!-----------------------------------------------------------------------
!     RELH       Surface air relative humidity (-).
!
      ij=0
      DO j=js,je
        DO i=is,ie
!
!         Calculate 2-m pressure using hypsometric equation. 
!         Assume temp at 2m = temp at 0m.
!
          cff1 = grid%PSFC(i,j)/(exp((9.81*2.0)/(287.0*grid%T2(i,j))))
!
!         Compute specific humidity using the 2-m mixing ratio and 
!         2-m pressure.
!
          rnum = grid%Q2(i,j)*cff1
          rden  = (grid%Q2(i,j)*(1.-0.622)+0.622)
          cff2 = rnum/rden
!
!         Compute saturation specific humidity using Bolton equation 10.
!
          c04 = 17.67*(grid%T2(i,j)-273.15)
          c05 = (grid%T2(i,j)-273.15) + 243.5
          cff3  = 6.112*exp(c04/c05)
!
          ij=ij+1
          cff=cff2/cff3
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "RELH",  &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     T2         Surface 2m air temperature (Convert to C).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%T2(i,j)-273.15
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "T2",    &
     &                           AA, Asize)
#  endif
!-----------------------------------------------------------------------
#  if defined BULK_FLUXES || defined ECOSIM
!     U10        U-Wind speed at 10 m (m s-1).
!     Rotate to earth lon lat.
!     
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%U10(i,j)*grid%cosa(i,j)-grid%V10(i,j)*grid%sina(i,j)
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "U10",   &
     &                           AA, Asize)
!
!-----------------------------------------------------------------------
!     V10        V-Wind speed at 10 m (m s-1).
!     Rotate to earth lon lat.
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%V10(i,j)*grid%cosa(i,j)+grid%U10(i,j)*grid%sina(i,j)
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "V10",   &
     &                           AA, Asize) 
#  endif
#  ifdef CLOUDS
!-----------------------------------------------------------------------
!     CLDFRA     Cloud fraction (--, 0-1.0).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%CLDFRA(i,1,j)
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "CLDFRA",&
     &                           AA, Asize)
#  endif
#  if !defined ANA_RAIN && defined EMINUSP
!-----------------------------------------------------------------------
!     RAIN       Precipitation (Convert to m s-1).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=0.001*(grid%RAINCV(i,j)+grid%RAINNCV(i,j))/grid%dt
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "RAIN",  &
     &                           AA, Asize)
#  endif
#  if defined EMINUSP
!-----------------------------------------------------------------------
!     EVAP      Evaporation (kg/m2 to Convert to m s-1).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
!         AA(ij)=0.001*(grid%SFCEVP(i,j))/grid%dt
          cff=0.001*(grid%QFX(i,j))
#   ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#   endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_O(ia,io)%atm2ocn_AV, "EVAP",  &
     &                           AA, Asize)
#  endif
!-----------------------------------------------------------------------
!  Send fields to ocean model.
!
      Tag=io*100+ia*10+0
#  ifdef MOVE_NESTS
      IF (moving_nest(ia).eq.1) THEN
        CALL MCT_MatVecMul(AttrVect_O(ia,io)%atm2ocn_AV,                &
     &                     SMPlus_R(ia)%F2CMatPlus,                     &
     &                     AV2_RO(ia,io)%fin2crs_AV2)
!
        CALL MCT_isend (AV2_RO(ia,io)%fin2crs_AV2,                      &
     &                  Router_O(ia,io)%WRFtoROMS, Tag)
      ELSE
#  endif
        CALL MCT_isend (AttrVect_O(ia,io)%atm2ocn_AV,                   &
     &                  Router_O(ia,io)%WRFtoROMS, Tag)
#  ifdef MOVE_NESTS
      END IF
#  endif
!
      CALL MCT_waits (Router_O(ia,io)%WRFtoROMS)
      IF (MYRANK.EQ.0) THEN
        WRITE (*,36) ' ## WRF grid ',ia,                                &
     &                    ' sent data to ROMS grid ',io
 36     FORMAT (a14,i2,a24,i2)
      ENDIF
      IF (MyError.ne.0) THEN
        WRITE (*,*) 'coupling send fail atm_coupler, error= ', MyError
        CALL finalize_atm_coupling
      END IF
!
!  Deallocate communication arrays.
!
      deallocate (AA)
#  ifdef MOVE_NESTS
      deallocate (MOV_MASK)
#  endif
      RETURN
      END SUBROUTINE atm2ocn_coupling
# endif

# if defined SWAN_COUPLING || defined WW3_COUPLING
      SUBROUTINE atm2wav_coupling (grid, ia, iw)
!
!=======================================================================
!                                                                      !
!  This subroutine reads and writes the coupled data streams.          !
!  Currently, the following data streams are processed:                !
!                                                                      !
!  Possible fields exported to the OCEAN Model:                        !
!                                                                      !
!     * GSW        Short wave raditaion  (Watts/m2)                    !
!     * GLW        Long wave raditaion  (Watts/m2)                     !
!     * LH         Latent heat flux     (Watts/m2)                     !
!     * HFX        Sensible heat flux   (Watts/m2)                     !
!     * USTRESS    Surface U-wind stress (Pa)                          !
!     * VSTRESS    Surface v-stress      (Pa)                          !
!     * MSLP       Mean Sea Level Pressure (Pa)                        !
!     * RELH       Surface air relative humidity (percent)             !
!     * T2         Surface 2m air temperature (Celsius)                !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!     * CLDFRA     Cloud fraction       (percent/100)                  !
!     * RAIN       Precipitation        (m/s)                          !
!     * EVAP       Evaporation          (m/s)                          !
!                                                                      !
!  Fields exported to the WAVE Model:                                  !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!                                                                      !
!  Fields acquired from the WAVE Model:                                !
!                                                                      !
!     * HISGN      Significant wave heigth (m)                         !
!     * WLENP      Peak wave length (m)                                !
!     * RTP        Peak wave period (s)                                !
!                                                                      !
!  Fields acquired from the OCEAN Model:                               !
!                                                                      !
!     * SST        Sea surface temperature                             !
!=======================================================================
!
      USE module_domain
!
      implicit none
!     TYPE(domain) , INTENT (IN) :: grid 
      TYPE(domain) , POINTER     :: grid            ! jcw check this
#  ifdef MOVE_NESTS
      TYPE(domain) , POINTER     :: grid_ptr
#  endif
      integer, intent(in) :: ia, iw
!
!  Local variable declarations.
!
      integer :: is, ie, js, je, ij, Tag
      integer :: MyStatus, i, j, Asize, ierr, MyRank
      integer :: MyError, MySize, indx, Istr, Iend, Jstr, Jend
      integer :: Isize, Jsize, nprocs, offset
#  ifdef MOVE_NESTS
      integer :: count, jc, num_sparse_elems
#  endif

      real, parameter :: eps=1.0e-10
      real :: cff
      real, pointer :: AA(:)
#  ifdef MOVE_NESTS
      real, pointer :: MOV_MASK(:,:)
#  endif
!
!  Set grid range.
!
      is = grid%sp31
      ie = grid%ep31
      js = grid%sp33
      je = grid%ep33
      IF (grid%ed31.eq.ie) THEN
        ie=ie-1
      END IF
      IF (grid%ed33.eq.je) THEN
        je=je-1
      END IF
!
!-----------------------------------------------------------------------
!  Send atmosphere fields to SWAN.
!-----------------------------------------------------------------------
!
      CALL MPI_COMM_RANK (ATM_COMM_WORLD, MyRank, MyError)
      CALL MPI_COMM_SIZE (ATM_COMM_WORLD, nprocs, MyError)
!
!  Get the number of grid point on this processor.
!
      Asize=GlobalSegMap_lsize(GlobalSegMap_G(ia)%GSMapWRF,             &
     &                         ATM_COMM_WORLD)
!
!  Allocate attribute vector array used to export/import data.
!
      allocate ( AA(Asize), stat=ierr )
!
#  ifdef MOVE_NESTS
!  If we have a moving nest, then need to mask out parent location of
!  the child nest.
!
      allocate ( MOV_MASK(is:ie,js:je), stat=ierr )
      DO i=is,ie
        DO j=js,je
          MOV_MASK(i,j)=1.0
        END DO
      END DO
!  Get Istr and Jstr of moving child in parent grid.
!  Allow parent to provide one more row around child perimeter.


!  want to know:
!  1 - do you have a child that is moving?
!  2  - if so, then where is it now?

        IF (ia.eq.parent_id(Natm_grids)) THEN
          CALL find_grid_by_id(Natm_grids, grid, grid_ptr)
          offset=1
          Istr=grid_ptr%i_parent_start+offset
          Jstr=grid_ptr%j_parent_start+offset
          ij=full_Isize(Natm_grids)/par_grid_ratio(Natm_grids)
          Iend=grid_ptr%i_parent_start+ij-1-offset
          ij=full_Jsize(Natm_grids)/par_grid_ratio(Natm_grids)
          Jend=grid_ptr%j_parent_start+ij-1-offset
!
          IF ((Istr.ge.is).or.(Istr.le.ie)) THEN
            IF ((Jstr.ge.js).or.(Jstr.le.je)) THEN
              DO i=MAX(is,Istr),MIN(Iend,ie)
                DO j=MAX(js,Jstr),MIN(Jend,je)
                  MOV_MASK(i,j)=0.0
                END DO
              END DO
            END IF
          END IF
        END IF
!
!  Adjust the sparse matrices here.
!
!       IF (ia.eq.Natm_grids) THEN
        IF ((Myrank.eq.0).and.(moving_nest(ia).eq.1)) THEN

!  First the fine to coarse
          src_grid_dims(1)=full_Isize(ia)
          src_grid_dims(2)=full_Jsize(ia)
          dst_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          dst_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
          num_sparse_elems=src_grid_dims(1)*src_grid_dims(2)
          allocate ( sparse_rows(num_sparse_elems) )
!
          Istr=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          Jstr=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,src_grid_dims(2)
            count=(Jstr-1+j-1)*(dst_grid_dims(1))+Istr-1
            DO i=1,src_grid_dims(1)
              jc=jc+1
              sparse_rows(jc)=count+i
            END DO
          END DO
          call SparseMatrix_importGRowInd(sMatF, sparse_rows,           &
     &                                    num_sparse_elems)
          deallocate ( sparse_rows )
!
! Second the coarse to fine.
!
          dst_grid_dims(1)=full_Isize(ia)
          dst_grid_dims(2)=full_Jsize(ia)
          src_grid_dims(1)=full_Isize(parent_id(ia))*par_grid_ratio(ia)
          src_grid_dims(2)=full_Jsize(parent_id(ia))*par_grid_ratio(ia)
          num_sparse_elems=dst_grid_dims(1)*dst_grid_dims(2)
          allocate ( sparse_cols(num_sparse_elems) )
          Istr=(grid%i_parent_start-1)*par_grid_ratio(ia)+1
          Jstr=(grid%j_parent_start-1)*par_grid_ratio(ia)+1
          jc=0
          DO j=1,dst_grid_dims(2)
            count=(Jstr-1+j-1)*(src_grid_dims(1))+Istr-1
            DO i=1,dst_grid_dims(1)
              jc=jc+1
              sparse_cols(jc)=count+i
            END DO
          END DO
          call SparseMatrix_importGColInd(sMatC, sparse_cols,           &
     &                                    num_sparse_elems)
          deallocate ( sparse_cols )
        END IF
        IF (moving_nest(ia).eq.1) THEN
!  reinit the matrices
          call SparseMatrixPlus_clean(SMPlus_R(ia)%F2CMatPlus)
          call SparseMatrixPlus_init(SMPlus_R(ia)%F2CMatPlus, sMatF,    &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
!
          call SparseMatrixPlus_clean(SMPlus_R(ia)%C2FMatPlus)
          call SparseMatrixPlus_init(SMPlus_R(ia)%C2FMatPlus, sMatC,    &
     &                               GSMapInterp_R(ia)%GSMapStatic,     &
     &                               GlobalSegMap_G(ia)%GSMapWRF,       &
     &                               Xonly, 0, ATM_COMM_WORLD, ATMid)
        END IF
#  endif
!-----------------------------------------------------------------------
!  Send U10 and V10 to SWAN.
!-----------------------------------------------------------------------
!     U10        U-Wind speed at 10 m (m s-1).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%U10(i,j)*grid%cosa(i,j)-grid%V10(i,j)*grid%sina(i,j)
#  ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#  endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_W(ia,iw)%atm2wav_AV, "U10",   &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!     V10        V-Wind speed at 10 m (m s-1).
!
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=grid%V10(i,j)*grid%cosa(i,j)+grid%U10(i,j)*grid%sina(i,j)
#  ifdef MOVE_NESTS
          cff=cff*MOV_MASK(i,j)
#  endif
          AA(ij)=cff
        END DO
      END DO
      CALL AttrVect_importRAttr (AttrVect_W(ia,iw)%atm2wav_AV, "V10",   &
     &                           AA, Asize)
!-----------------------------------------------------------------------
!
      Tag=0+ia*10+iw
#  ifdef MOVE_NESTS
      IF (moving_nest(ia).eq.1) THEN
        CALL MCT_MatVecMul(AttrVect_W(ia,iw)%atm2wav_AV,                &
     &                     SMPlus_R(ia)%F2CMatPlus,                     &
     &                     AV2_RW(ia,iw)%fin2crs_AV2)
!
        CALL MCT_isend (AV2_RW(ia,iw)%fin2crs_AV2,                      &
     &                  Router_W(ia,iw)%WRFtoSWAN, Tag)
      ELSE
#  endif
        CALL MCT_isend (AttrVect_W(ia,iw)%atm2wav_AV,                   &
     &                  Router_W(ia,iw)%WRFtoSWAN, Tag)
#  ifdef MOVE_NESTS
      END IF
#  endif
!
      CALL MCT_waits (Router_W(ia,iw)%WRFtoSWAN)
      IF (MYRANK.EQ.0) THEN
        WRITE (*,37) ' ## WRF grid ',ia,                                &
     &                    ' sent data to WAVE grid ',iw
 37     FORMAT (a14,i2,a24,i2)
      ENDIF
      IF (MyError.ne.0) THEN
        WRITE (*,*) 'coupling send fail atm_coupler, error= ', MyError
        CALL finalize_atm_coupling
      END IF
!
!  Deallocate communication arrays.
!
      deallocate (AA)
      RETURN
      END SUBROUTINE atm2wav_coupling
# endif

# ifdef ROMS_COUPLING
      SUBROUTINE atmfocn_coupling (grid, ia, io, aux4flag)
!
!=======================================================================
!                                                                      !
!  This subroutine reads and writes the coupled data streams.          !
!  Currently, the following data streams are processed:                !
!                                                                      !
!  Possible fields exported to the OCEAN Model:                        !
!                                                                      !
!     * GSW        Short wave raditaion  (Watts/m2)                    !
!     * GLW        Long wave raditaion  (Watts/m2)                     !
!     * LH         Latent heat flux     (Watts/m2)                     !
!     * HFX        Sensible heat flux   (Watts/m2)                     !
!     * USTRESS    Surface U-wind stress (Pa)                          !
!     * VSTRESS    Surface v-stress      (Pa)                          !
!     * MSLP       Mean Sea Level Pressure (Pa)                        !
!     * RELH       Surface air relative humidity (percent)             !
!     * T2         Surface 2m air temperature (Celsius)                !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!     * CLDFRA     Cloud fraction       (percent/100)                  !
!     * RAIN       Precipitation        (m/s)                          !
!     * EVAP       Evaporation          (m/s)                          !
!                                                                      !
!  Fields exported to the WAVE Model:                                  !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!                                                                      !
!  Fields acquired from the WAVE Model:                                !
!                                                                      !
!     * HISGN      Significant wave heigth (m)                         !
!     * WLENP      Peak wave length (m)                                !
!     * RTP        Peak wave period (s)                                !
!                                                                      !
!  Fields acquired from the OCEAN Model:                               !
!                                                                      !
!     * SST        Sea surface temperature                             !
!=======================================================================
!
      USE module_domain
!
      implicit none
      TYPE(domain) , INTENT (IN) :: grid 
      integer, intent(in) :: ia, io, aux4flag
!
!  Local variable declarations.
!
      integer :: is, ie, js, je, ij, Tag
      integer :: MyStatus, i, j, Asize, ierr, MyRank
      integer :: MyError, MySize, indx, Istr, Iend, Jstr, Jend
      integer :: Isize, Jsize, nprocs

      real, parameter :: eps=1.0e-10
      real, parameter ::  Large = 1.0E+20
      real :: cff, inval, retval
      real, pointer :: AA(:)
      real, pointer :: Amask(:)
      real, dimension(2) :: range
!  Set grid range.
!
      is = grid%sp31
      ie = grid%ep31
      js = grid%sp33
      je = grid%ep33
      IF (grid%ed31.eq.ie) THEN
        ie=ie-1
      END IF
      IF (grid%ed33.eq.je) THEN
        je=je-1
      END IF
!
!-----------------------------------------------------------------------
!  Send atmosphere fields to ROMS.
!-----------------------------------------------------------------------
!
      CALL MPI_COMM_RANK (ATM_COMM_WORLD, MyRank, MyError)
      CALL MPI_COMM_SIZE (ATM_COMM_WORLD, nprocs, MyError)
!
!  Get the number of grid point on this processor.
!
      Asize=GlobalSegMap_lsize(GlobalSegMap_G(ia)%GSMapWRF,             &
     &                         ATM_COMM_WORLD)
!
!  Allocate attribute vector array used to export/import data.
!
      allocate ( AA(Asize), stat=ierr )
      allocate ( Amask(Asize), stat=ierr )
!
!  Schedule receiving fields from ocean model.
!  For now, use this aux4flag to do update if sst_update is used.
!
      IF (aux4flag.eq.0) THEN
        Tag=io*100+ia*10+0
#  ifdef MOVE_NESTS
        IF (moving_nest(ia).eq.1) THEN
          CALL MCT_irecv (AV2_RO(ia,io)%crs2fin_AV2,                    &
     &                    Router_O(ia,io)%WRFtoROMS, Tag)
! Wait to make sure the WRF data has arrived.
          CALL MCT_waitr (AV2_RO(ia,io)%crs2fin_AV2,                    &
     &                    Router_O(ia,io)%WRFtoROMS)
          CALL MCT_MatVecMul(AV2_RO(ia,io)%crs2fin_AV2,                 &
     &                       SMPlus_R(ia)%C2FMatPlus,                   &
     &                       AttrVect_O(ia,io)%ocn2atm_AV)
        ELSE
#  endif
          CALL MCT_irecv (AttrVect_O(ia,io)%ocn2atm_AV,                 &
     &                    Router_O(ia,io)%WRFtoROMS,Tag)
! Wait to make sure the OCN data has arrived.
          CALL MCT_waitr (AttrVect_O(ia,io)%ocn2atm_AV,                 &
     &                    Router_O(ia,io)%WRFtoROMS)
#  ifdef MOVE_NESTS
        END IF
#  endif
!
        IF (MYRANK.EQ.0) THEN
          WRITE (*,38) ' ## WRF grid ',ia,                              &
     &                      ' recvd data from ROMS grid ',io
 38       FORMAT (a13,i2,a27,i2)
        END IF
        IF (MyError.ne.0) THEN
          WRITE (*,*) 'coupling fail wrfcplr, MyStatus= ', MyError
          CALL finalize_atm_coupling
        END IF
      END IF
!
 40         FORMAT (a36,1x,2(1pe14.6))
!  SST (Convert to K).
!  USE CPLMASK:  coupling mask (0 for data read in wrflowinput,
!                               1 data received from the coupler)
#  ifdef MCT_INTERP_OC2AT
      CALL AttrVect_exportRAttr (AttrVect_O(ia,io)%ocn2atm_AV,          &
     &                           "CPL_MASK", AA, Asize)
#  endif
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
#  ifdef SST_CONST
          Amask(ij)=0.
#  else
#   ifdef MCT_INTERP_OC2AT
          Amask(ij)=AA(ij)
#   else
          Amask(ij)=1.
#   endif
#  endif
        END DO
      END DO
!
      CALL AttrVect_exportRAttr (AttrVect_O(ia,io)%ocn2atm_AV,          &
     &                           "SST", AA, Asize)
      range(1)= Large
      range(2)=-Large
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=(AA(ij)+273.15)*Amask(ij)
          grid%sst(i,j)=cff+grid%sst(i,j)*(1.0-Amask(ij))
          range(1)=MIN(range(1),cff)
          range(2)=MAX(range(2),cff)
        END DO
      END DO
      IF (aux4flag.eq.0) THEN
        CALL mpi_allreduce ( range(1), retval , 1, MPI_REAL,            &
     &                       MPI_MIN, ATM_COMM_WORLD, ierr )
        range(1)=retval
        CALL mpi_allreduce ( range(2), retval , 1, MPI_REAL,            &
     &                       MPI_MAX, ATM_COMM_WORLD, ierr )
        range(2)=retval
        IF (Myrank.eq.0) THEN
          write(*,40) 'ROMStoWRF  Min/Max SST     (K):     ',           &
     &                      range(1),range(2)
        END IF
      END IF
!
!  Deallocate communication arrays.
!
      deallocate (AA)
      deallocate (Amask)
      RETURN
      END SUBROUTINE atmfocn_coupling
# endif

# if defined SWAN_COUPLING || defined WW3_COUPLING
      SUBROUTINE atmfwav_coupling (grid, ia, iw)
!
!=======================================================================
!                                                                      !
!  This subroutine reads and writes the coupled data streams.          !
!  Currently, the following data streams are processed:                !
!                                                                      !
!  Possible fields exported to the OCEAN Model:                        !
!                                                                      !
!     * GSW        Short wave raditaion  (Watts/m2)                    !
!     * GLW        Long wave raditaion  (Watts/m2)                     !
!     * LH         Latent heat flux     (Watts/m2)                     !
!     * HFX        Sensible heat flux   (Watts/m2)                     !
!     * USTRESS    Surface U-wind stress (Pa)                          !
!     * VSTRESS    Surface v-stress      (Pa)                          !
!     * MSLP       Mean Sea Level Pressure (Pa)                        !
!     * RELH       Surface air relative humidity (percent)             !
!     * T2         Surface 2m air temperature (Celsius)                !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!     * CLDFRA     Cloud fraction       (percent/100)                  !
!     * RAIN       Precipitation        (m/s)                          !
!     * EVAP       Evaporation          (m/s)                          !
!                                                                      !
!  Fields exported to the WAVE Model:                                  !
!     * U10        U-Wind speed at 10 m (m/s)                          !
!     * V10        V-Wind speed at 10 m (m/s)                          !
!                                                                      !
!  Fields acquired from the WAVE Model:                                !
!                                                                      !
!     * HISGN      Significant wave heigth (m)                         !
!     * WLENP      Peak wave length (m)                                !
!     * RTP        Peak wave period (s)                                !
!                                                                      !
!  Fields acquired from the OCEAN Model:                               !
!                                                                      !
!     * SST        Sea surface temperature                             !
!=======================================================================
!
      USE module_domain
!
      implicit none
      TYPE(domain) , INTENT (IN) :: grid 
      integer, intent(in) :: ia, iw
!
!  Local variable declarations.
!
      integer :: is, ie, js, je, ij, Tag
      integer :: MyStatus, i, j, Asize, ierr, MyRank
      integer :: MyError, MySize, indx, Istr, Iend, Jstr, Jend
      integer :: Isize, Jsize, nprocs

      real, parameter :: eps=1.0e-10
      real, pointer :: AA(:)
      real, parameter ::  Large = 1.0E+20
      real :: cff, inval, retval
      real, dimension(2) :: range
#  ifdef MCT_INTERP_WV2AT
      real, pointer :: Amask(:)
#  endif
!
!  Set grid range.
!
      is = grid%sp31
      ie = grid%ep31
      js = grid%sp33
      je = grid%ep33
      IF (grid%ed31.eq.ie) THEN
        ie=ie-1
      END IF
      IF (grid%ed33.eq.je) THEN
        je=je-1
      END IF
!
!-----------------------------------------------------------------------
!  Send atmosphere fields to ROMS.
!-----------------------------------------------------------------------
!
      CALL MPI_COMM_RANK (ATM_COMM_WORLD, MyRank, MyError)
      CALL MPI_COMM_SIZE (ATM_COMM_WORLD, nprocs, MyError)
!
!  Get the number of grid point on this processor.
!
      Asize=GlobalSegMap_lsize(GlobalSegMap_G(ia)%GSMapWRF,             &
     &                         ATM_COMM_WORLD)
!
!  Allocate attribute vector array used to export/import data.
!
      allocate ( AA(Asize), stat=ierr )
#  ifdef MCT_INTERP_WV2AT
      allocate ( Amask(Asize), stat=ierr )
#  endif
!
!  Schedule receiving fields from wave model.
!
      Tag=0+ia*10+iw
#  ifdef MOVE_NESTS
      IF (moving_nest(ia).eq.1) THEN
        CALL MCT_irecv (AV2_RW(ia,iw)%crs2fin_AV2,                      &
     &                  Router_W(ia,iw)%WRFtoSWAN, Tag)
!  Wait to make sure the WRF data has arrived.
        CALL MCT_waitr (AV2_RW(ia,iw)%crs2fin_AV2,                      &
     &                  Router_W(ia,iw)%WRFtoSWAN)
        CALL MCT_MatVecMul(AV2_RW(ia,iw)%crs2fin_AV2,                   &
     &                     SMPlus_R(ia)%C2FMatPlus,                     &
     &                     AttrVect_W(ia,iw)%wav2atm_AV)
      ELSE
#  endif
        CALL MCT_irecv (AttrVect_W(ia,iw)%wav2atm_AV,                   &
     &                  Router_W(ia,iw)%WRFtoSWAN, Tag)
!  Wait to make sure the WAV data has arrived.
        CALL MCT_waitr (AttrVect_W(ia,iw)%wav2atm_AV,                   &
     &                   Router_W(ia,iw)%WRFtoSWAN)
#  ifdef MOVE_NESTS
      END IF
#  endif
!
      IF (MYRANK.EQ.0) THEN
        WRITE (*,30) ' ## WRF grid ',ia,                                &
     &                    ' recv data from WAVE grid ',iw
 30     FORMAT (a14,i2,a26,i2)
      END IF
      IF (MyError.ne.0) THEN
        WRITE (*,*) 'coupl fail wrfcplr, MyStatus= ', MyError
        CALL finalize_atm_coupling
      END IF
 40         FORMAT (a36,1x,2(1pe14.6))
!
!  CPL_MASK
!
#  ifdef MCT_INTERP_WV2AT
      CALL AttrVect_exportRAttr (AttrVect_W(ia,iw)%wav2atm_AV,          &
     &                           "CPL_MASK", AA, Asize)
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          Amask(ij)=AA(ij)
        END DO
      END DO
#  endif
!
!  Hwave.
!
      CALL AttrVect_exportRAttr (AttrVect_W(ia,iw)%wav2atm_AV, "HSIGN", &
     &                           AA, Asize)
      range(1)= Large
      range(2)=-Large
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=MAX(0.0,AA(ij))
#  ifdef MCT_INTERP_WV2AT
          grid%hwave(i,j)=cff*Amask(ij)+                                &
     &                    grid%hwave(i,j)*(1.0-Amask(ij))
#  else
          grid%hwave(i,j)=cff
#  endif
          range(1)=MIN(range(1),cff)
          range(2)=MAX(range(2),cff)
        END DO
      END DO
      CALL mpi_allreduce ( range(1), retval , 1, MPI_REAL,              &
     &                     MPI_MIN, ATM_COMM_WORLD, ierr )
      range(1)=retval
      CALL mpi_allreduce ( range(2), retval , 1, MPI_REAL,              &
     &                     MPI_MAX, ATM_COMM_WORLD, ierr )
      range(2)=retval
      IF (Myrank.eq.0) THEN
        write(*,40) 'WAVtoWRF  Min/Max HSIGN   (m):     ',              &
     &                    range(1),range(2)
      END IF
!
!  Lwave.
!
      CALL AttrVect_exportRAttr (AttrVect_W(ia,iw)%wav2atm_AV, "WLENP", &
     &                           AA, Asize)
      range(1)= Large
      range(2)=-Large
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=MAX(0.0,AA(ij))
#  ifdef MCT_INTERP_WV2AT
          grid%lwavep(i,j)=cff*Amask(ij)+                   &
     &                     grid%lwavep(i,j)*(1.0-Amask(ij))
#  else
          grid%lwavep(i,j)=cff
#  endif
          range(1)=MIN(range(1),cff)
          range(2)=MAX(range(2),cff)
        END DO
      END DO
      CALL mpi_allreduce ( range(1), retval , 1, MPI_REAL,              &
     &                     MPI_MIN, ATM_COMM_WORLD, ierr )
      range(1)=retval
      CALL mpi_allreduce ( range(2), retval , 1, MPI_REAL,              &
     &                     MPI_MAX, ATM_COMM_WORLD, ierr )
      range(2)=retval
      IF (Myrank.eq.0) THEN
        write(*,40) 'WAVtoWRF  Min/Max WLENP   (m):     ',              &
     &                    range(1),range(2)
      END IF
!
!  Pwave_top.
!
      CALL AttrVect_exportRAttr (AttrVect_W(ia,iw)%wav2atm_AV, "RTP",   &
     &                           AA, Asize)
      range(1)= Large
      range(2)=-Large
      ij=0
      DO j=js,je
        DO i=is,ie
          ij=ij+1
          cff=MAX(0.0,AA(ij))
#  ifdef MCT_INTERP_WV2AT
          grid%pwave(i,j)=cff*Amask(ij)+                    &
     &                     grid%pwave(i,j)*(1.0-Amask(ij))
#  else
          grid%pwave(i,j)=cff
#  endif
          range(1)=MIN(range(1),cff)
          range(2)=MAX(range(2),cff)
        END DO
      END DO
      CALL mpi_allreduce ( range(1), retval , 1, MPI_REAL,              &
     &                     MPI_MIN, ATM_COMM_WORLD, ierr )
      range(1)=retval
      CALL mpi_allreduce ( range(2), retval , 1, MPI_REAL,              &
     &                     MPI_MAX, ATM_COMM_WORLD, ierr )
      range(2)=retval
      IF (Myrank.eq.0) THEN
        write(*,40) 'WAVtoWRF  Min/Max RTP     (m):     ',              &
     &                    range(1),range(2)
      END IF
!
!  Deallocate communication arrays.
!
      deallocate (AA)
#  ifdef MCT_INTERP_WV2AT
      deallocate (Amask)
#  endif
      RETURN
      END SUBROUTINE atmfwav_coupling
#endif

      SUBROUTINE finalize_atm_coupling
!
!=======================================================================
!                                                                    ===
!  This routines terminates execution during coupling error.         ===
!                                                                    ===
!=======================================================================
!
      implicit none
!
!  Local variable declarations.
!
      integer :: ia, io, iw, MyStatus
!
!-----------------------------------------------------------------------
!  Terminate MPI execution environment.
!-----------------------------------------------------------------------
!
!     CALL Router_clean (RoutWRFtoROMS)
      DO ia=1,Natm_grids
        CALL GlobalSegMap_clean (GlobalSegMap_G(ia)%GSMapWRF)
# ifdef ROMS_COUPLING
        DO io=1,Nocn_grids
          CALL AttrVect_clean (AttrVect_O(ia,io)%atm2ocn_AV)
          CALL AttrVect_clean (AttrVect_O(ia,io)%ocn2atm_AV)
        END DO
# endif
# if defined SWAN_COUPLING || defined WW3_COUPLING
        DO iw=1,Nwav_grids
          CALL AttrVect_clean (AttrVect_W(ia,iw)%atm2wav_AV)
          CALL AttrVect_clean (AttrVect_W(ia,iw)%wav2atm_AV)
        END DO
# endif
      END DO
!     CALL MCTWorld_clean ()

      END SUBROUTINE finalize_atm_coupling
#endif
      END MODULE atm_coupler_mod