!=
!
!= Rearrangement of column
!
! Authors::   Yoshiyuki O. Takahashi
! Version::   $Id: rearrange_column.F90,v 1.1 2014/06/29 07:21:02 yot Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2008. All rights reserved.
! License::   See COPYRIGHT[link:../../../COPYRIGHT]
!

module rearrange_column
  !
  !=
  !
  != Rearrangement of column
  !
  ! <b>Note that Japanese and English are described in parallel.</b>
  !
  !
  !
  ! Rearrange columns
  !
  !== Procedures List
  !
!!$  ! IntLonLat_xy           :: ç·¯åº¦çµŒåº¦ç©åˆ†
!!$  ! y_IntLon_xy, IntLon_x  :: çµŒåº¦ç©åˆ†
!!$  ! ya_IntLon_xya          :: çµŒåº¦ç©åˆ† (å¤šå±¤ç”¨)
!!$  ! x_IntLat_xy, IntLat_y  :: ç·¯åº¦ç©åˆ†
!!$  ! xa_IntLat_xya          :: ç·¯åº¦ç©åˆ† (å¤šå±¤ç”¨)
!!$  ! AvrLonLat_xy           :: ç·¯åº¦çµŒåº¦å¹³å‡
!!$  ! y_AvrLon_xy, AvrLon_x  :: çµŒåº¦å¹³å‡
!!$  ! ya_AvrLon_xya          :: çµŒåº¦å¹³å‡ (å¤šå±¤ç”¨)
!!$  ! x_AvrLat_xy, AvrLat_y  :: ç·¯åº¦å¹³å‡
!!$  ! xa_AvrLat_xya          :: ç·¯åº¦å¹³å‡ (å¤šå±¤ç”¨)
  ! ---------------------  :: ---------------------
!!$  ! y_IntLon_xy, IntLon_x  :: Meridional integral
!!$  ! ya_IntLon_xya          :: Meridional integral (for multi layer)
!!$  ! x_IntLat_xy, IntLat_y  :: Zonal integral
!!$  ! xa_IntLat_xya          :: Zonal integral (for multi layer)
!!$  ! AvrLonLat_xy           :: Zonal and meridional average
!!$  ! y_AvrLon_xy, AvrLon_x  :: Meridional average
!!$  ! ya_AvrLon_xya          :: Meridional average (for multi layer)
!!$  ! x_AvrLat_xy, AvrLat_y  :: Zonal average
!!$  ! xa_AvrLat_xya          :: Zonal average (for multi layer)
  !
  !--
  !== NAMELIST
  !
  ! NAMELIST#rearrange_column_nml
  !++

  ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨ ; USE statements
  !

  ! æ ¼åç‚¹è¨å®š
  ! Grid points settings
  !
!!$  use gridset, only: imax, & ! çµŒåº¦æ ¼åç‚¹æ•°.
!!$                             ! Number of grid points in longitude
!!$    &                jmax, & ! ç·¯åº¦æ ¼åç‚¹æ•°.
!!$                             ! Number of grid points in latitude
!!$    &                kmax    ! é‰›ç›´å±¤æ•°.
!!$                             ! Number of vertical level

  ! ç¨®åˆ¥åž‹ãƒ‘ãƒ©ãƒ¡ã‚¿
  ! Kind type parameter
  !
  use dc_types, only: DP, &      ! å€ç²¾åº¦å®Ÿæ•°åž‹. Double precision.
    &                 STRING     ! æ–‡å—åˆ—.       Strings.

  ! ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸å‡ºåŠ›
  ! Message output
  !
  use dc_message, only: MessageNotify

  ! å®£è¨€æ–‡ ; Declaration statements
  !
  implicit none
  private

  ! å…¬é–‹æ‰‹ç¶šã
  ! Public procedure
  !
  public:: RearrangeColumn

  ! å…¬é–‹å¤‰æ•°
  ! Public variables
  !
  logical, save, public:: rearrange_column_inited = .false.
                              ! åˆæœŸè¨å®šãƒ•ãƒ©ã‚°.
                              ! Initialization flag

  ! éžå…¬é–‹å¤‰æ•°
  ! Private variables
  !

  character(*), parameter:: module_name = 'rearrange_column'
                              ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®åç§°.
                              ! Module name
  character(*), parameter:: version = &
    & '$Name:  $' // &
    & '$Id: rearrange_column.F90,v 1.1 2014/06/29 07:21:02 yot Exp $'
                              ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³
                              ! Module version

  ! INTERFACE æ–‡ ; INTERFACE statements
  !

contains

  !-------------------------------------------------------------------

#ifdef LIB_MPI

  subroutine RearrangeColumn( &
    & xya_Data &
    & )
    !
    ! Rearrange columns
    !

    ! MPI
    !
    use mpi_wrapper, only: nprocs, myrank, &
      & MPIWrapperISend, &
      & MPIWrapperIRecv, &
      & MPIWrapperWait

    real(DP), intent(inout) :: xya_Data(:,:,:)

    ! ä½œæ¥å¤‰æ•°
    ! Work variables
    !
    real(DP), allocatable :: xyaa_SendBuf(:,:,:,:)
    real(DP), allocatable :: xyaa_RecvBuf(:,:,:,:)

    integer :: imaxLocal
    integer :: jmaxLocal
    integer :: kmaxLocal

    integer :: imaxBlock

    integer :: iLocal

    integer :: a_iReqSend(0:nprocs-1)
    integer :: a_iReqRecv(0:nprocs-1)

    integer:: i               ! çµŒåº¦æ–¹å‘ã«å›žã‚‹ DO ãƒ«ãƒ¼ãƒ—ç”¨ä½œæ¥å¤‰æ•°
                              ! Work variables for DO loop in longitudinal direction
    integer:: j               ! ç·¯åº¦æ–¹å‘ã«å›žã‚‹ DO ãƒ«ãƒ¼ãƒ—ç”¨ä½œæ¥å¤‰æ•°
                              ! Work variables for DO loop in latitudinal direction
    integer:: n

    ! å®Ÿè¡Œæ–‡ ; Executable statement
    !

    imaxLocal = size( xya_Data, 1 )
    jmaxLocal = size( xya_Data, 2 )
    kmaxLocal = size( xya_Data, 3 )

    if ( mod( imaxLocal/2, nprocs ) /= 0 ) then
      call MessageNotify( 'E', module_name, 'nprocs value is inappropriate, nprocs = %d', i = (/ nprocs /) )
    end if
    if ( mod( imaxLocal/2/nprocs, 2 ) /= 0 ) then
      call MessageNotify( 'E', module_name, 'nprocs value is inappropriate, nprocs = %d', i = (/ nprocs /) )
    end if

    imaxBlock = imaxLocal / nprocs

    allocate( xyaa_SendBuf(1:imaxBlock,1:jmaxLocal,1:kmaxLocal,0:nprocs-1) )
    allocate( xyaa_RecvBuf(1:imaxBlock,1:jmaxLocal,1:kmaxLocal,0:nprocs-1) )

    ! pack data transfered to nth process
    do n = 0, nprocs-1
      iLocal = 1
      do i = n+1, imaxLocal, nprocs
        xyaa_SendBuf(iLocal,:,:,n) = xya_Data(i,:,:)
        iLocal = iLocal + 1
      end do
    end do

    do n = 0, nprocs-1
      xyaa_RecvBuf = xyaa_SendBuf
    end do

    do n = 0, nprocs-1
      if ( n == myrank ) then
        xyaa_RecvBuf(:,:,:,n) = xyaa_SendBuf(:,:,:,n)
      else
        call MPIWrapperISend( n, imaxBlock, jmaxLocal, kmaxLocal, xyaa_SendBuf(:,:,:,n), a_iReqSend(n) )
        call MPIWrapperIRecv( n, imaxBlock, jmaxLocal, kmaxLocal, xyaa_RecvBuf(:,:,:,n), a_iReqRecv(n) )
      end if
    end do
    do n = 0, nprocs-1
      if ( n == myrank ) cycle
      call MPIWrapperWait( a_iReqSend(n) )
      call MPIWrapperWait( a_iReqRecv(n) )
    end do

    ! pack data transfered to nth process
    do n = 0, nprocs-1
      iLocal = 1
      do i = n+1, imaxLocal, nprocs
        xya_Data(i,:,:) = xyaa_RecvBuf(iLocal,:,:,n)
        iLocal = iLocal + 1
      end do
    end do

    deallocate( xyaa_SendBuf )
    deallocate( xyaa_RecvBuf )

  end subroutine RearrangeColumn

#else

  subroutine RearrangeColumn( &
    & xya_Data  &
    & )
    !
    ! Rearrange columns
    !

    real(DP), intent(inout) :: xya_Data (:,:,:)

    ! ä½œæ¥å¤‰æ•°
    ! Work variables
    !

    ! å®Ÿè¡Œæ–‡ ; Executable statement
    !

  end subroutine RearrangeColumn

#endif

  !--------------------------------------------------------------------------------------

end module rearrange_column