advection_mod sourceΒΆ

   1MODULE advection_mod
   2  ! MODULE advection_mod (prefix='adv' category='4. Data Object transformations')
   3  !
   4  !:Purpose:  To perform forward and/or backward advection (based on 
   5  !           semi-lagrangian trajectories) for both gridStateVector and
   6  !           ensemble of gridStateVectors
   7  !
   8  use ramDisk_mod
   9  use midasMpi_mod
  10  use mathPhysConstants_mod
  11  use earthConstants_mod
  12  use ensembleStateVector_mod
  13  use gridStateVector_mod
  14  use gridStateVectorFileIO_mod
  15  use horizontalCoord_mod
  16  use verticalCoord_mod
  17  use utilities_mod
  18  use varNameList_mod
  19  implicit none
  20  save
  21  private
  22
  23  ! public procedures
  24  public :: struct_adv, adv_Setup
  25  public :: adv_ensemble_tl, adv_ensemble_ad
  26  public :: adv_statevector_tl, adv_statevector_ad
  27
  28  type :: struct_adv_LevType
  29    integer, allocatable :: lonIndex       (:,:,:) ! lon, lat, lev
  30    integer, allocatable :: latIndex       (:,:,:)
  31    real(8), allocatable :: interpWeight_BL(:,:,:)
  32    real(8), allocatable :: interpWeight_BR(:,:,:)
  33    real(8), allocatable :: interpWeight_TL(:,:,:)
  34    real(8), allocatable :: interpWeight_TR(:,:,:)
  35  end type struct_adv_LevType
  36
  37  type :: struct_adv_timeStep
  38    type(struct_adv_LevType), allocatable :: levType(:) 
  39  end type struct_adv_timeStep
  40
  41  type :: struct_adv
  42    private
  43    integer :: nLev_M
  44    integer :: nLev_T
  45    integer :: ni, nj
  46    integer :: lonPerPE, lonPerPEmax, myLonBeg, myLonEnd
  47    integer :: latPerPE, latPerPEmax, myLatBeg, myLatEnd
  48    integer, allocatable :: allLonBeg(:), allLatBeg(:)
  49    integer :: nTimeStep
  50    integer :: timeStepIndexMainSource
  51    integer, allocatable :: timeStepIndexSource(:)
  52    logical :: singleTimeStepIndexSource
  53    type(struct_adv_timeStep), allocatable :: timeStep(:)
  54  end type struct_adv
  55
  56  integer, external  :: get_max_rss
  57
  58  integer, parameter :: MMindex = 1
  59  integer, parameter :: THindex = 2
  60  integer, parameter :: SFindex = 3
  61
  62  real(8), parameter :: numGridPts    =  1.0d0 ! used to compute numSubStep
  63  real(8), parameter :: latitudePatch = 80.0d0 ! this defines latitude where rotated grid used
  64
  65  integer :: numStepSteeringFlow
  66  integer :: lonPerPE, latPerPE
  67  integer, allocatable :: allLonBeg(:), allLatBeg(:)
  68  integer, allocatable :: numSubStep(:)
  69
  70  real(8), pointer     :: uu_steeringFlow_ptr4d(:,:,:,:)
  71  real(8), pointer     :: vv_steeringFlow_ptr4d(:,:,:,:)
  72  real(8), allocatable :: uu_steeringFlow_mpiGlobal(:,:,:)
  73  real(8), allocatable :: vv_steeringFlow_mpiGlobal(:,:,:)
  74  real(8), allocatable :: uu_steeringFlow_ThermoLevel(:,:)
  75  real(8), allocatable :: vv_steeringFlow_ThermoLevel(:,:)
  76
  77  real(8), allocatable :: steeringFlowFactor(:)
  78
  79  real(8) :: steeringFlowDelTsec
  80
  81  type(struct_hco), pointer :: hco
  82  type(struct_vco), pointer :: vco
  83
  84  logical :: nlat_equalAcrossMpiTasks, nlon_equalAcrossMpiTasks
  85
  86  ! Control parameter for the level of listing output
  87  logical, parameter :: verbose = .false.
  88
  89CONTAINS
  90
  91  !--------------------------------------------------------------------------
  92  ! adv_Setup
  93  !--------------------------------------------------------------------------
  94  SUBROUTINE adv_setup(adv, mode, hco_in, vco_in, numStepAdvectedField, &
  95                       dateStampListAdvectedField, numStepSteeringFlow_in, steeringFlowDelThour, &
  96                       steeringFlowFactor_in, levTypeList, steeringFlowFilename_opt, &
  97                       statevector_steeringFlow_opt)
  98    implicit none
  99
 100    ! Arguments:
 101    type(struct_adv),           intent(inout) :: adv
 102    type(struct_hco), pointer,  intent(in) :: hco_in
 103    type(struct_vco), pointer,  intent(in) :: vco_in
 104    character(len=*),           intent(in) :: mode
 105    character(len=*),           intent(in) :: levTypeList
 106    character(len=*), optional, intent(in) :: steeringFlowFilename_opt
 107    integer,                    intent(in) :: numStepAdvectedField
 108    integer,                    intent(in) :: numStepSteeringFlow_in
 109    integer,                    intent(in) :: dateStampListAdvectedField(numStepAdvectedField)
 110    real(8),                    intent(in) :: steeringFlowFactor_in(vco_in%nLev_M)
 111    real(8),                    intent(in) :: steeringFlowDelThour
 112    type(struct_gsv), optional, intent(inout) :: statevector_steeringFlow_opt
 113
 114    ! Locals:
 115    integer :: latIndex0, lonIndex0, latIndex, lonIndex, levIndex, stepIndexSF, stepIndexAF, ierr
 116    integer :: levIndexBelow, levIndexAbove
 117    integer :: gdxyfll, gdllfxy
 118    integer :: nLevType
 119    integer, allocatable :: dateStampListSteeringFlow(:)
 120    integer, allocatable :: advectedFieldAssociatedStepIndexSF(:)
 121    integer, allocatable :: advectionSteeringFlowStartingStepIndex(:)
 122    integer, allocatable :: advectionSteeringFlowEndingStepIndex  (:)
 123    real(8) :: interpWeight_BL, interpWeight_BR, interpWeight_TL, interpWeight_TR
 124    real(8), allocatable :: uu_steeringFlow_mpiGlobalTiles(:,:,:,:)
 125    real(8), allocatable :: vv_steeringFlow_mpiGlobalTiles(:,:,:,:)
 126    real(4) :: xpos_r4, ypos_r4, xposTH_r4, yposTH_r4
 127    real(4) :: lonMMbelow_deg_r4, lonMMabove_deg_r4, latMMbelow_deg_r4, latMMabove_deg_r4, lonTH_deg_r4, latTH_deg_r4 
 128    real(4), allocatable :: xposMM_r4(:,:,:,:), yposMM_r4(:,:,:,:)
 129    character(len=1024) :: filename
 130
 131    type(struct_gsv) :: statevector_steeringFlow
 132    logical :: AdvectFileExists
 133    integer :: nLev, levTypeIndex, stepIndexSF_start, stepIndexSF_end 
 134    integer :: myLonBeg, myLonEnd
 135    integer :: myLatBeg, myLatEnd
 136
 137    !
 138    !- 1.  Set low-level variables
 139    !
 140    numStepSteeringFlow   = numStepSteeringFlow_in
 141    adv%nTimeStep         = numStepAdvectedField
 142
 143    allocate(steeringFlowFactor(vco_in%nLev_M))
 144    do levIndex = 1, vco_in%nLev_M
 145      steeringFlowFactor(levIndex) = steeringFlowFactor_in(levIndex)
 146      write(*,*) 'adv_setup: steeringFlowFactor = ', levIndex, steeringFlowFactor(levIndex)
 147    end do
 148
 149    allocate(adv%timeStepIndexSource(numStepAdvectedField))
 150
 151    if (vco_in%Vcode /= 5002 .and. vco_in%Vcode /= 5005 ) then
 152      call utl_abort('adv_setup: Only vCode 5002 and 5005 are currently supported!')
 153    end if
 154
 155    select case(trim(levTypeList))
 156    case ('MMLevsOnly')
 157      nLevType = 1
 158    case ('allLevs')
 159      nLevType = 3
 160    case default
 161      write(*,*)
 162      write(*,*) 'Unsupported levTypeList: ', trim(levTypeList)
 163      call utl_abort('adv_setup')
 164    end select
 165    
 166    !- 1.1 Mode
 167    select case(trim(mode))
 168    case ('fromFirstTimeIndex')
 169      adv%timeStepIndexMainSource  = 1
 170      adv%timeStepIndexSource(:)   = adv%timeStepIndexMainSource
 171      adv%singleTimeStepIndexSource= .true.
 172    case ('fromMiddleTimeIndex')
 173      if (mod(numStepAdvectedField,2) == 0) then
 174        call utl_abort('adv_setup: numStepAdvectedField cannot be even with direction=fromMiddleTimeIndex') 
 175      end if
 176      adv%timeStepIndexMainSource  = (numStepAdvectedField+1)/2
 177      adv%timeStepIndexSource(:)   = adv%timeStepIndexMainSource
 178      adv%singleTimeStepIndexSource= .true.
 179    case ('fromLastTimeIndex')
 180      adv%timeStepIndexMainSource  = numStepAdvectedField
 181      adv%timeStepIndexSource(:)   = adv%timeStepIndexMainSource
 182      adv%singleTimeStepIndexSource= .true.
 183    case ('towardFirstTimeIndex','towardFirstTimeIndexInverse')
 184      adv%timeStepIndexMainSource = 1
 185      do stepIndexAF = 1, numStepAdvectedField
 186        adv%timeStepIndexSource(stepIndexAF) = stepIndexAF
 187      end do
 188      adv%singleTimeStepIndexSource = .false.
 189    case('towardMiddleTimeIndex','towardMiddleTimeIndexInverse')
 190      if (mod(numStepAdvectedField,2) == 0) then
 191        call utl_abort('adv_setup: numStepAdvectedField cannot be even with direction=towardMiddleTimeIndex') 
 192      end if
 193      adv%timeStepIndexMainSource = (numStepAdvectedField+1)/2
 194      do stepIndexAF = 1, numStepAdvectedField
 195        adv%timeStepIndexSource(stepIndexAF) = stepIndexAF
 196      end do
 197      adv%singleTimeStepIndexSource = .false.
 198    case default
 199      write(*,*)
 200      write(*,*) 'Unsupported mode : ', trim(mode)
 201      call utl_abort('adv_setup')
 202    end select
 203
 204    !- Set some important values
 205    steeringFlowDelTsec = steeringFlowDelThour*3600.0D0
 206
 207    !- 1.2 Grid Size
 208    hco => hco_in
 209    adv%ni = hco%ni
 210    adv%nj = hco%nj
 211    vco => vco_in
 212    adv%nLev_M = vco%nLev_M
 213    adv%nLev_T = vco%nLev_T
 214
 215    call mmpi_setup_latbands(adv%nj, adv%latPerPE, adv%latPerPEmax, adv%myLatBeg, adv%myLatEnd, & 
 216         divisible_opt=nlat_equalAcrossMpiTasks)
 217    call mmpi_setup_lonbands(adv%ni, adv%lonPerPE, adv%lonPerPEmax, adv%myLonBeg, adv%myLonEnd, &
 218         divisible_opt=nlon_equalAcrossMpiTasks)
 219    allocate(adv%allLonBeg(mmpi_npex))
 220    call rpn_comm_allgather(adv%myLonBeg,1,"mpi_integer",       &
 221         adv%allLonBeg,1,"mpi_integer","EW",ierr)
 222    allocate(adv%allLatBeg(mmpi_npey))
 223    call rpn_comm_allgather(adv%myLatBeg,1,"mpi_integer",       &
 224         adv%allLatBeg,1,"mpi_integer","NS",ierr)
 225
 226    lonPerPE = adv%lonPerPE 
 227    latPerPE = adv%latPerPE
 228    allocate(allLonBeg(mmpi_npex))
 229    allocate(allLatBeg(mmpi_npey))
 230    allLonBeg(:) = adv%allLonBeg(:)
 231    allLatBeg(:) = adv%allLatBeg(:)
 232
 233    !- 1.3 Memory allocation
 234    myLonBeg = adv%myLonBeg
 235    myLonEnd = adv%myLonEnd
 236    myLatBeg = adv%myLatBeg
 237    myLatEnd = adv%myLatEnd
 238
 239    nLev = adv%nLev_M
 240
 241    allocate(adv%timeStep(numStepAdvectedField))
 242
 243    do stepIndexAF = 1, numStepAdvectedField
 244
 245      if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
 246
 247      allocate(adv%timeStep(stepIndexAF)%levType(nLevType))
 248      do levTypeIndex = 1,  nLevType ! ( 1=MM, 2=TH, 3=SF )
 249        if      (levTypeIndex == MMindex ) then
 250          nLev = adv%nLev_M
 251        else if (levTypeIndex == THindex) then
 252          nLev = adv%nLev_T
 253        else
 254          nLev = 1
 255        end if
 256        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex       (myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 257        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex       (myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 258        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 259        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 260        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 261        allocate(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nLev))
 262        adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(:,:,:) = 1.0d0
 263        adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(:,:,:) = 0.0d0
 264        adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(:,:,:) = 0.0d0
 265        adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(:,:,:) = 0.0d0
 266      end do
 267    end do
 268
 269    !
 270    !- 2.  Read in the wind data to use for advection
 271    !
 272    allocate(dateStampListSteeringFlow(numStepSteeringFlow))
 273
 274    if (present(steeringFlowFilename_opt) ) then
 275
 276      if (mmpi_myid == 0)  then
 277        write(*,*)
 278        write(*,*) 'steeringFlow source taken from input file = ', trim(steeringFlowFilename_opt) 
 279      end if
 280
 281      do stepIndexSF = 1, numStepSteeringFlow
 282        call incdatr(dateStampListSteeringFlow(stepIndexSF), dateStampListAdvectedField(1), &
 283                     real(stepIndexSF-1,8)*steeringFlowDelThour)
 284      end do
 285
 286      call gsv_allocate(statevector_steeringFlow,numStepSteeringFlow, hco, vco, &
 287                        dateStampList_opt=dateStampListSteeringFlow, &
 288                        varNames_opt=(/'UU','VV','P0'/), mpi_local_opt=.true., &
 289                        hInterpolateDegree_opt='LINEAR')
 290      
 291      fileName = ram_fullWorkingPath(trim(steeringFlowFilename_opt))
 292      inquire(file=trim(fileName),exist=AdvectFileExists)
 293      write(*,*) 'AdvectFileExists', AdvectFileExists
 294      do stepIndexSF = 1, numStepSteeringFlow
 295        call gio_readFromFile( statevector_steeringFlow, fileName, ' ', ' ', stepIndex_opt=stepIndexSF, &
 296                               containsFullField_opt=.true.)
 297      end do
 298
 299      ierr = ram_remove(fileName)
 300
 301      call gsv_getField(statevector_steeringFlow, uu_steeringFlow_ptr4d, 'UU')
 302      call gsv_getField(statevector_steeringFlow, vv_steeringFlow_ptr4d, 'VV')
 303
 304    else if (present(statevector_steeringFlow_opt)) then
 305
 306      if (mmpi_myid == 0)  then
 307        write(*,*)
 308        write(*,*) 'steeringFlow source = input gridStateVector'
 309        write(*,*) numStepSteeringFlow
 310        write(*,*) statevector_steeringFlow_opt%dateStampList(:)
 311      end if
 312      dateStampListSteeringFlow(:) = statevector_steeringFlow_opt%dateStampList(:)
 313      call gsv_getField(statevector_steeringFlow_opt, uu_steeringFlow_ptr4d, 'UU')
 314      call gsv_getField(statevector_steeringFlow_opt, vv_steeringFlow_ptr4d, 'VV')
 315
 316    else
 317      call utl_abort('adv_setup: steeringFlow source was not provided!')
 318    end if
 319
 320    !
 321    !-  3.  Advection setup
 322    !
 323
 324    !-  3.1 Match the stepIndex between the reference flow and the fields to be advected
 325    allocate(advectedFieldAssociatedStepIndexSF(numStepAdvectedField))
 326    advectedFieldAssociatedStepIndexSF(:) = -1
 327    do stepIndexAF = 1, numStepAdvectedField
 328      do stepIndexSF = 1, numStepSteeringFlow
 329        if ( dateStampListAdvectedField(stepIndexAF) == dateStampListSteeringFlow(stepIndexSF) ) then
 330          advectedFieldAssociatedStepIndexSF(stepIndexAF) = stepIndexSF
 331          if (mmpi_myid == 0)  then
 332            write(*,*)
 333            write(*,*) 'stepIndex Match', stepIndexAF, stepIndexSF
 334          end if
 335          exit 
 336        end if
 337      end do
 338      if ( advectedFieldAssociatedStepIndexSF(stepIndexAF) == -1 ) then
 339        call utl_abort('adv_setup: no match between dateStampListAdvectedField and dateStampListSteeringFlow')
 340      end if
 341    end do
 342
 343    !-  3.2 Set starting, ending and direction parameters
 344    allocate(advectionSteeringFlowStartingStepIndex(numStepAdvectedField))
 345    allocate(advectionSteeringFlowEndingStepIndex  (numStepAdvectedField))
 346
 347    select case(trim(mode))
 348    case ('fromFirstTimeIndex','fromMiddleTimeIndex','fromLastTimeIndex', &
 349          'towardFirstTimeIndexInverse','towardMiddleTimeIndexInverse')
 350      do stepIndexAF = 1, numStepAdvectedField
 351        advectionSteeringFlowStartingStepIndex(stepIndexAF) = advectedFieldAssociatedStepIndexSF(adv%timeStepIndexMainSource)
 352        advectionSteeringFlowEndingStepIndex  (stepIndexAF) = advectedFieldAssociatedStepIndexSF(stepIndexAF)
 353      end do
 354    case ('towardFirstTimeIndex','towardMiddleTimeIndex')
 355      do stepIndexAF = 1, numStepAdvectedField
 356        advectionSteeringFlowStartingStepIndex(stepIndexAF) = advectedFieldAssociatedStepIndexSF(stepIndexAF)
 357        advectionSteeringFlowEndingStepIndex  (stepIndexAF) = advectedFieldAssociatedStepIndexSF(adv%timeStepIndexMainSource)
 358      end do
 359    case default
 360      write(*,*)
 361      write(*,*) 'Oops! This should never happen. Check the code...'
 362      call utl_abort('adv_setup')
 363    end select
 364
 365    !
 366    !- 4.  Perform the advection (backward and/or forward) 
 367    !
 368    if (mmpi_myid == 0) write(*,*) 'setupAdvectAmplitude: starting'
 369    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 370
 371    allocate(numSubStep(adv%nj))
 372    allocate(uu_steeringFlow_mpiGlobal(numStepSteeringFlow, adv%ni, adv%nj))
 373    allocate(vv_steeringFlow_mpiGlobal(numStepSteeringFlow, adv%ni, adv%nj))
 374
 375    allocate(uu_steeringFlow_mpiGlobalTiles(numStepSteeringFlow, adv%lonPerPE, adv%latPerPE, mmpi_nprocs))
 376    allocate(vv_steeringFlow_mpiGlobalTiles(numStepSteeringFlow, adv%lonPerPE, adv%latPerPE, mmpi_nprocs))
 377    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 378
 379    if ( nLevType >= THindex ) then
 380      allocate(xposMM_r4(numStepSteeringFlow,myLonBeg:myLonEnd,myLatBeg:myLatEnd,adv%nLev_M))
 381      allocate(yposMM_r4(numStepSteeringFlow,myLonBeg:myLonEnd,myLatBeg:myLatEnd,adv%nLev_M))
 382    end if
 383
 384    !- 4.1 Compute the trajectories on the momentum levels
 385    levTypeIndex = MMindex
 386    nLev         = adv%nLev_M
 387
 388    do levIndex = 1, nLev ! loop over levels
 389      
 390      if (mmpi_myid == 0) write(*,*) 'setupAdvectAmplitude: levIndex = ', levIndex
 391
 392      call processSteeringFlow(levTypeIndex, levIndex,                                         & ! IN
 393                               uu_steeringFlow_mpiGlobalTiles, vv_steeringFlow_mpiGlobalTiles, & ! OUT
 394                               adv%nLev_M, adv%nLev_T, myLatBeg, myLatEnd)                       ! IN
 395
 396      do stepIndexAF = 1, numStepAdvectedField
 397        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
 398
 399        stepIndexSF_start = advectionSteeringFlowStartingStepIndex(stepIndexAF)
 400        stepIndexSF_end   = advectionSteeringFlowEndingStepIndex  (stepIndexAF) 
 401
 402        ! loop over all initial grid points within tile for determining trajectories
 403        do latIndex0 = adv%myLatBeg, adv%myLatEnd
 404          do lonIndex0 = adv%myLonBeg, adv%myLonEnd
 405
 406            call calcTrajectory(xpos_r4, ypos_r4,                                                 & ! OUT
 407                                latIndex0, lonIndex0, levIndex, stepIndexSF_start, stepIndexSF_end) ! IN
 408
 409            if ( nLevType >= THindex ) then
 410              xposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndex) = xpos_r4
 411              yposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndex) = ypos_r4
 412            end if
 413            
 414            call calcWeights(lonIndex, latIndex, interpWeight_BL, interpWeight_BR,   & ! OUT
 415                             interpWeight_TL, interpWeight_TR,                       & ! OUT
 416                             xpos_r4, ypos_r4)                                         ! IN
 417
 418            ! store the final position of the trajectory and interp weights
 419            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex       (lonIndex0,latIndex0,levIndex) = lonIndex
 420            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex       (lonIndex0,latIndex0,levIndex) = latIndex
 421            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex0,latIndex0,levIndex) = interpWeight_BL
 422            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex0,latIndex0,levIndex) = interpWeight_BR
 423            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex0,latIndex0,levIndex) = interpWeight_TL
 424            adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex0,latIndex0,levIndex) = interpWeight_TR
 425
 426          end do ! lonIndex0
 427        end do ! latIndex0
 428
 429      end do ! stepIndexAF
 430
 431    end do ! levIndex
 432
 433    !- 4.2 Thermodynamic levels: Interpolate vertically the positions found on the momentum levels
 434    if ( nLevType >= THindex ) then
 435      levTypeIndex = THindex
 436      nLev         = adv%nLev_T
 437
 438      do levIndex = 1, nLev ! loop over levels
 439        do stepIndexAF = 1, numStepAdvectedField
 440          if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
 441
 442          do latIndex0 = adv%myLatBeg, adv%myLatEnd
 443            do lonIndex0 = adv%myLonBeg, adv%myLonEnd
 444
 445              if (levIndex == 1 .and. vco%Vcode == 5002) then
 446                ! use top momentum level amplitudes for top thermo level
 447                xposTH_r4 = xposMM_r4(stepIndexAF,lonIndex0,latIndex0,1)
 448                yposTH_r4 = yposMM_r4(stepIndexAF,lonIndex0,latIndex0,1)
 449              else if (levIndex == nLev) then
 450                ! use surface momentum level amplitudes for surface thermo level
 451                xposTH_r4 = xposMM_r4(stepIndexAF,lonIndex0,latIndex0,adv%nLev_M)
 452                yposTH_r4 = yposMM_r4(stepIndexAF,lonIndex0,latIndex0,adv%nLev_M)
 453              else
 454                ! for other levels, interpolate momentum positions to get thermo positions (as in GEM)
 455                if (vco%Vcode == 5002) then
 456                  levIndexBelow = levIndex
 457                  levIndexAbove = levIndex-1
 458                else
 459                  levIndexBelow = levIndex+1
 460                  levIndexAbove = levIndex
 461                end if
 462
 463                ierr = gdllfxy(hco%EZscintID, latMMbelow_deg_r4, lonMMbelow_deg_r4, &
 464                               xposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndexBelow), &
 465                               yposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndexBelow), 1) 
 466
 467                ierr = gdllfxy(hco%EZscintID, latMMabove_deg_r4, lonMMabove_deg_r4, &
 468                               xposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndexAbove), &
 469                               yposMM_r4(stepIndexAF,lonIndex0,latIndex0,levIndexAbove), 1)
 470
 471                if (lonMMbelow_deg_r4 < 0.0) lonMMbelow_deg_r4 = lonMMbelow_deg_r4 + 360.0
 472                if (lonMMabove_deg_r4 < 0.0) lonMMabove_deg_r4 = lonMMabove_deg_r4 + 360.0
 473
 474                if ( abs(lonMMbelow_deg_r4 - lonMMabove_deg_r4) > 180.0 ) then
 475                  if (lonMMbelow_deg_r4 > 180.0 ) then
 476                    lonMMbelow_deg_r4 = lonMMbelow_deg_r4 - 360.0
 477                  else
 478                    lonMMabove_deg_r4 = lonMMabove_deg_r4 - 360.0
 479                  end if
 480                end if
 481                lonTH_deg_r4 = 0.5 * (lonMMbelow_deg_r4 + lonMMabove_deg_r4)
 482                if (lonTH_deg_r4 < 0.0) lonTH_deg_r4 = lonTH_deg_r4 + 360.0
 483                latTH_deg_r4 = 0.5 * (latMMbelow_deg_r4 + latMMabove_deg_r4)
 484
 485                ierr = gdxyfll(hco%EZscintID, xposTH_r4, yposTH_r4, &
 486                               latTH_deg_r4, lonTH_deg_r4, 1)
 487              end if
 488
 489              ! Compute weights
 490              call calcWeights(lonIndex, latIndex, interpWeight_BL, interpWeight_BR,   & ! OUT
 491                               interpWeight_TL, interpWeight_TR,                       & ! OUT
 492                               xposTH_r4, yposTH_r4)                                     ! IN
 493
 494              ! Store the final position of the trajectory and interp weights
 495              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex       (lonIndex0,latIndex0,levIndex) = lonIndex
 496              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex       (lonIndex0,latIndex0,levIndex) = latIndex
 497              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex0,latIndex0,levIndex) = interpWeight_BL
 498              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex0,latIndex0,levIndex) = interpWeight_BR
 499              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex0,latIndex0,levIndex) = interpWeight_TL
 500              adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex0,latIndex0,levIndex) = interpWeight_TR
 501            end do
 502          end do
 503        end do
 504      end do
 505
 506      deallocate(xposMM_r4)
 507      deallocate(yposMM_r4)
 508
 509    end if
 510
 511    !- 4.3 Surface level: Use the positions from the lowest momentum levels
 512    if ( nLevType == SFindex ) then
 513      do stepIndexAF = 1, numStepAdvectedField
 514        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
 515        adv%timeStep(stepIndexAF)%levType(SFindex)%lonIndex       (:,:,1) = &
 516             adv%timeStep(stepIndexAF)%levType(MMindex)%lonIndex       (:,:,adv%nLev_M)
 517        adv%timeStep(stepIndexAF)%levType(SFindex)%latIndex       (:,:,1) = &
 518             adv%timeStep(stepIndexAF)%levType(MMindex)%latIndex       (:,:,adv%nLev_M)
 519        adv%timeStep(stepIndexAF)%levType(SFindex)%interpWeight_BL(:,:,1) = &
 520             adv%timeStep(stepIndexAF)%levType(MMindex)%interpWeight_BL(:,:,adv%nLev_M)
 521        adv%timeStep(stepIndexAF)%levType(SFindex)%interpWeight_BR(:,:,1) = &
 522             adv%timeStep(stepIndexAF)%levType(MMindex)%interpWeight_BR(:,:,adv%nLev_M)
 523        adv%timeStep(stepIndexAF)%levType(SFindex)%interpWeight_TL(:,:,1) = &
 524             adv%timeStep(stepIndexAF)%levType(MMindex)%interpWeight_TL(:,:,adv%nLev_M)
 525        adv%timeStep(stepIndexAF)%levType(SFindex)%interpWeight_TR(:,:,1) = &
 526             adv%timeStep(stepIndexAF)%levType(MMindex)%interpWeight_TR(:,:,adv%nLev_M)
 527      end do
 528    end if
 529
 530    deallocate(numSubStep)
 531    deallocate(allLonBeg)
 532    deallocate(allLatBeg)
 533    deallocate(uu_steeringFlow_mpiGlobalTiles)
 534    deallocate(vv_steeringFlow_mpiGlobalTiles)
 535    deallocate(uu_steeringFlow_mpiGlobal)
 536    deallocate(vv_steeringFlow_mpiGlobal)
 537    if (present(steeringFlowFilename_opt) ) then
 538      call gsv_deallocate(statevector_steeringFlow)
 539    end if
 540
 541    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 542    if (mmpi_myid == 0) write(*,*) 'adv_setup: done'
 543
 544  end SUBROUTINE adv_setup
 545
 546  !--------------------------------------------------------------------------
 547  ! processSteeringFlow
 548  !--------------------------------------------------------------------------
 549  SUBROUTINE processSteeringFlow (levTypeIndex, levIndex, &
 550                                  uu_steeringFlow_mpiGlobalTiles, vv_steeringFlow_mpiGlobalTiles, &
 551                                  nLev_M, nLev_T, myLatBeg, myLatEnd)
 552    implicit none
 553
 554    ! Arguments:
 555    integer, intent(in)  :: levTypeIndex
 556    integer, intent(in)  :: levIndex
 557    integer, intent(in)  :: nLev_M
 558    integer, intent(in)  :: nLev_T
 559    integer, intent(in)  :: myLatBeg
 560    integer, intent(in)  :: myLatEnd
 561    real(8), intent(out) :: uu_steeringFlow_mpiGlobalTiles(:,:,:,:)
 562    real(8), intent(out) :: vv_steeringFlow_mpiGlobalTiles(:,:,:,:)
 563
 564    ! Locals:
 565    integer :: stepIndexSF, nsize, ierr 
 566    integer :: procID, procIDx, procIDy, lonIndex, latIndex
 567    integer :: lonIndex_mpiglobal, latIndex_mpiglobal
 568    integer :: levIndexBelow, levIndexAbove
 569    real(8) :: uu, vv, latAdvect
 570
 571    nsize = lonPerPE*latPerPE
 572
 573    if ( levTypeIndex == MMindex ) then
 574      ! No vertical interpolation is needed
 575      do stepIndexSF = 1, numStepSteeringFlow
 576        ! gather the winds for this level
 577        call rpn_comm_allgather(uu_steeringFlow_ptr4d(:,:,levIndex,stepIndexSF)  , nsize, "mpi_double_precision", &
 578                                uu_steeringFlow_mpiGlobalTiles(stepIndexSF,:,:,:), nsize, "mpi_double_precision", &
 579                                "GRID", ierr )
 580        call rpn_comm_allgather(vv_steeringFlow_ptr4d(:,:,levIndex,stepIndexSF)  , nsize, "mpi_double_precision", &
 581                                vv_steeringFlow_mpiGlobalTiles(stepIndexSF,:,:,:), nsize, "mpi_double_precision", &
 582                                "GRID", ierr )
 583      end do
 584    else if (levTypeIndex == THindex ) then
 585      ! Vertical interpolation is needed...
 586      ! The adopted approach follows the vertical interpolation for the amplitude fields in bMatrixEnsemble_mod
 587      do stepIndexSF = 1, numStepSteeringFlow
 588        if (levIndex == 1 .and. vco%Vcode == 5002) then
 589          ! use top momentum level amplitudes for top thermo level
 590          uu_steeringFlow_ThermoLevel(:,:) = uu_steeringFlow_ptr4d(:,:,1,stepIndexSF)
 591          vv_steeringFlow_ThermoLevel(:,:) = vv_steeringFlow_ptr4d(:,:,1,stepIndexSF)
 592        else if (levIndex == nLev_T) then
 593          ! use surface momentum level amplitudes for surface thermo level
 594          uu_steeringFlow_ThermoLevel(:,:) = uu_steeringFlow_ptr4d(:,:,nLev_M,stepIndexSF)
 595          vv_steeringFlow_ThermoLevel(:,:) = vv_steeringFlow_ptr4d(:,:,nLev_M,stepIndexSF)
 596        else
 597          ! for other levels, interpolate momentum winds to get thermo winds
 598          if (vco%Vcode == 5002) then
 599            levIndexBelow = levIndex
 600            levIndexAbove = levIndex-1
 601          else
 602            levIndexBelow = levIndex+1
 603            levIndexAbove = levIndex
 604          end if
 605          !$OMP PARALLEL DO PRIVATE (latIndex)
 606          do latIndex = myLatBeg, myLatEnd
 607            uu_steeringFlow_ThermoLevel(:,latIndex) = 0.5d0*( uu_steeringFlow_ptr4d(:,latIndex,levIndexAbove,stepIndexSF) + &
 608                 uu_steeringFlow_ptr4d(:,latIndex,levIndexBelow,stepIndexSF) )
 609            vv_steeringFlow_ThermoLevel(:,latIndex) = 0.5d0*( vv_steeringFlow_ptr4d(:,latIndex,levIndexAbove,stepIndexSF) + &
 610                 vv_steeringFlow_ptr4d(:,latIndex,levIndexBelow,stepIndexSF) )
 611          end do
 612          !$OMP END PARALLEL DO
 613        end if
 614
 615        ! gather the INTERPOLATED winds for this level
 616        call rpn_comm_allgather(uu_steeringFlow_ThermoLevel                      , nsize, "mpi_double_precision",  &
 617                                uu_steeringFlow_mpiGlobalTiles(stepIndexSF,:,:,:), nsize, "mpi_double_precision",  &
 618                                "GRID", ierr )
 619        call rpn_comm_allgather(uu_steeringFlow_ThermoLevel                      , nsize, "mpi_double_precision",  &
 620                                vv_steeringFlow_mpiGlobalTiles(stepIndexSF,:,:,:), nsize, "mpi_double_precision",  &
 621                                "GRID", ierr )
 622
 623      end do
 624
 625    else
 626      call utl_abort('processSteeringFlow: invalid levTypeIndex')
 627    end if
 628
 629    ! rearrange gathered winds for convenience
 630    do procIDy = 0, (mmpi_npey-1)
 631      do procIDx = 0, (mmpi_npex-1)
 632        procID = procIDx + procIDy*mmpi_npex
 633        do latIndex = 1, latPerPE
 634          latIndex_mpiglobal = latIndex + allLatBeg(procIDy+1) - 1
 635          do lonIndex = 1, lonPerPE
 636            lonIndex_mpiglobal = lonIndex + allLonBeg(procIDx+1) - 1
 637            uu_steeringFlow_mpiGlobal(:, lonIndex_mpiglobal, latIndex_mpiglobal) = uu_steeringFlow_mpiGlobalTiles(:, lonIndex, latIndex, procID+1)
 638            vv_steeringFlow_mpiGlobal(:, lonIndex_mpiglobal, latIndex_mpiglobal) = vv_steeringFlow_mpiGlobalTiles(:, lonIndex, latIndex, procID+1)
 639          end do
 640        end do
 641      end do
 642    end do
 643
 644    ! determine the number of time steps required as a function of latitude
 645    do latIndex = 1, hco%nj
 646      latAdvect = hco%lat(latIndex)
 647      if (abs(latAdvect) < latitudePatch*MPC_RADIANS_PER_DEGREE_R8) then
 648        uu = maxval(abs(uu_steeringFlow_mpiGlobal(:,:,latIndex) /(ec_ra*cos(latAdvect)))) ! in rad/s
 649        vv = maxval(abs(vv_steeringFlow_mpiGlobal(:,:,latIndex) / ec_ra)) ! in rad/s
 650      else
 651        uu = maxval(abs(uu_steeringFlow_mpiGlobal(:,:,latIndex) / ec_ra)) ! in rad/s
 652        vv = maxval(abs(vv_steeringFlow_mpiGlobal(:,:,latIndex) / ec_ra)) ! in rad/s
 653      end if
 654      numSubStep(latIndex) = max( 1,  &
 655           nint( (steeringFlowDelTsec * steeringFlowFactor(levIndex) * uu) / (numGridPts*(hco%lon(2)-hco%lon(1))) ),  &
 656           nint( (steeringFlowDelTsec * steeringFlowFactor(levIndex) * vv) / (numGridPts*(hco%lat(2)-hco%lat(1))) ) )
 657    end do
 658    if (mmpi_myid == 0) write(*,*) 'min and max of numSubStep',minval(numSubStep(:)),maxval(numSubStep(:))
 659
 660  end SUBROUTINE processSteeringFlow
 661
 662  !--------------------------------------------------------------------------
 663  ! calcTrajectory
 664  !--------------------------------------------------------------------------
 665  SUBROUTINE calcTrajectory(xpos_r4, ypos_r4, latIndex0, lonIndex0, &
 666                            levIndex, stepIndexSF_start, stepIndexSF_end)
 667    implicit none
 668
 669    ! Arguments:
 670    real(4), intent(out) :: xpos_r4
 671    real(4), intent(out) :: ypos_r4
 672    integer, intent(in)  :: latIndex0
 673    integer, intent(in)  :: lonIndex0
 674    integer, intent(in)  :: stepIndexSF_start
 675    integer, intent(in)  :: stepIndexSF_end
 676    integer, intent(in)  :: levIndex
 677
 678    ! Locals:
 679    integer :: subStepIndex, stepIndexSF, ierr, gdxyfll, latIndex, lonIndex
 680    integer :: alfa, ni, nj,  stepIndex_direction, stepIndex_first, stepIndex_last
 681    real(8) :: uu, vv, subDelT, lonAdvect, latAdvect
 682    real(8) :: uu_p, vv_p, lonAdvect_p, latAdvect_p, Gcoef, Scoef
 683    real(4) :: lonAdvect_deg_r4, latAdvect_deg_r4
 684
 685    ni = hco%ni
 686    nj = hco%nj
 687
 688    subDelT = steeringFlowDelTsec/real(numSubStep(latIndex0),8)  ! in seconds
 689
 690    ! position at the initial time of back trajectory
 691    lonAdvect = hco%lon(lonIndex0)  ! in radians
 692    latAdvect = hco%lat(latIndex0)
 693    lonIndex = lonIndex0  ! index
 694    latIndex = latIndex0
 695    xpos_r4 = real(lonIndex,4)
 696    ypos_r4 = real(latIndex,4)
 697
 698    ! initial positions in rotated coordinate system
 699    lonAdvect_p = 0.0d0
 700    latAdvect_p = 0.0d0
 701
 702    if (verbose) then
 703      write(*,*) 'final lonAdvect,latAdvect=', &
 704           lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 705           latAdvect*MPC_DEGREES_PER_RADIAN_R8
 706      write(*,*) 'numSubStep=', numSubStep(latIndex0)
 707    end if
 708
 709    ! time stepping strategy
 710    if      (stepIndexSF_end > stepIndexSF_start) then
 711      ! back trajectory   , stepping backwards
 712      stepIndex_first     = stepIndexSF_end-1
 713      stepIndex_last      = stepIndexSF_start
 714      stepIndex_direction = -1
 715    else if (stepIndexSF_end < stepIndexSF_start) then
 716      ! forward trajectory, stepping forward
 717      stepIndex_first     = stepIndexSF_end
 718      stepIndex_last      = stepIndexSF_start-1
 719      stepIndex_direction = 1
 720    else
 721      call utl_abort('calcTrajAndWeights: fatal error with stepIndexSF')
 722    end if
 723
 724    do stepIndexSF = stepIndex_first, stepIndex_last, stepIndex_direction
 725
 726      if (verbose) write(*,*) 'stepIndexSF,lonIndex,latIndex=',stepIndexSF,lonIndex,latIndex
 727
 728      do subStepIndex = 1, numSubStep(latIndex0)
 729
 730        alfa = (subStepIndex-1)/numSubStep(latIndex0)
 731        ! perform one timestep
 732        if (abs(hco%lat(latIndex0)) < latitudePatch*MPC_RADIANS_PER_DEGREE_R8) then
 733          ! points away from pole, handled normally
 734          ! determine wind at current location (now at BL point)
 735          uu = (  alfa *uu_steeringFlow_mpiGlobal(stepIndexSF  ,lonIndex,latIndex) + &
 736               (1-alfa)*uu_steeringFlow_mpiGlobal(stepIndexSF+1,lonIndex,latIndex) ) &
 737               /(ec_ra*cos(hco%lat(latIndex))) ! in rad/s
 738          vv = (   alfa*vv_steeringFlow_mpiGlobal(stepIndexSF  ,lonIndex,latIndex) + &
 739               (1-alfa)*vv_steeringFlow_mpiGlobal(stepIndexSF+1,lonIndex,latIndex) ) &
 740               /ec_ra
 741          ! apply user-specified scale factor to advecting winds
 742          uu = steeringFlowFactor(levIndex) * uu
 743          vv = steeringFlowFactor(levIndex) * vv
 744
 745          ! compute next position
 746          lonAdvect = lonAdvect + real(stepIndex_direction,8)*subDelT*uu  ! in radians
 747          latAdvect = latAdvect + real(stepIndex_direction,8)*subDelT*vv
 748
 749          if (verbose) then
 750            write(*,*) 'not near pole, lonAdvect,latAdvect,uu,vv=', &
 751                 lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 752                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,uu,vv
 753          end if
 754        else
 755          ! points near pole, handled in a special way
 756          ! determine wind at current location (now at BL point)
 757          uu =    alfa *uu_steeringFlow_mpiGlobal(stepIndexSF  ,lonIndex,latIndex) + &
 758               (1-alfa)*uu_steeringFlow_mpiGlobal(stepIndexSF+1,lonIndex,latIndex)  ! in m/s
 759          vv =    alfa *vv_steeringFlow_mpiGlobal(stepIndexSF  ,lonIndex,latIndex) + &
 760               (1-alfa)*vv_steeringFlow_mpiGlobal(stepIndexSF+1,lonIndex,latIndex)
 761          ! transform wind vector into rotated coordinate system
 762          Gcoef = ( cos(latAdvect)*cos(hco%lat(latIndex0)) + &
 763               sin(latAdvect)*sin(hco%lat(latIndex0))*cos(lonAdvect-hco%lon(lonIndex0)) ) / &
 764               cos(latAdvect_p)
 765          Scoef = ( sin(hco%lat(latIndex0))*sin(lonAdvect-hco%lon(lonIndex0)) ) / &
 766               cos(latAdvect_p)
 767          uu_p = Gcoef * uu - Scoef * vv ! in m/s
 768          vv_p = Scoef * uu + Gcoef * vv 
 769
 770          ! apply user-specified scale factor to advecting winds
 771          uu_p = steeringFlowFactor(levIndex) * uu_p ! in m/s
 772          vv_p = steeringFlowFactor(levIndex) * vv_p
 773
 774          ! compute next position (in rotated coord system)
 775          lonAdvect_p = lonAdvect_p + real(stepIndex_direction,8)*subDelT*uu_p/(ec_ra*cos(latAdvect_p))  ! in radians
 776          latAdvect_p = latAdvect_p + real(stepIndex_direction,8)*subDelT*vv_p/ec_ra
 777
 778          if (verbose) then
 779            write(*,*) '    near pole, uu_p,vv_p,Gcoef,Scoef=', &
 780                 uu_p, vv_p, Gcoef, Scoef
 781            write(*,*) '    near pole, lonAdvect_p,latAdvect_p=', &
 782                 lonAdvect_p*MPC_DEGREES_PER_RADIAN_R8, &
 783                 latAdvect_p*MPC_DEGREES_PER_RADIAN_R8
 784          end if
 785
 786          ! compute lon/lat in original coordinate system
 787          lonAdvect = hco%lon(lonIndex0) +                                                  &
 788               atan2( cos(latAdvect_p)*sin(lonAdvect_p) ,                            &
 789               ( cos(latAdvect_p)*cos(lonAdvect_p)*cos(hco%lat(latIndex0)) -  &
 790               sin(latAdvect_p)*sin(hco%lat(latIndex0)) ) )
 791          latAdvect = asin( cos(latAdvect_p)*cos(lonAdvect_p)*sin(hco%lat(latIndex0)) + &
 792               sin(latAdvect_p)*cos(hco%lat(latIndex0)) )
 793
 794          if (verbose) then
 795            write(*,*) '    near pole, lonAdvect,latAdvect=', &
 796                 lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 797                 latAdvect*MPC_DEGREES_PER_RADIAN_R8
 798          end if
 799        end if
 800
 801        ! convert lon/lat position into index
 802        lonAdvect_deg_r4 = real(lonAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 803        latAdvect_deg_r4 = real(latAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 804        ierr = gdxyfll(hco%EZscintID, xpos_r4, ypos_r4, &
 805                       latAdvect_deg_r4, lonAdvect_deg_r4, 1)
 806
 807        ! determine the bottom-left grid point
 808        lonIndex = floor(xpos_r4)
 809        latIndex = floor(ypos_r4)
 810
 811        ! check if position is east of the grid
 812        if (floor(xpos_r4) > ni) then
 813          if (verbose) then
 814            write(*,*) 'lonIndex0,latIndex0,lon,lat,stepIndexSF,x,y xpos_r4 > ni :', &
 815                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 816                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 817          end if
 818          ! add 10*epsilon(real*4) to ensure do not go too far due to limited precision
 819          lonAdvect = lonAdvect - 2.0D0*MPC_PI_R8 + 10.0D0*real(epsilon(1.0),8)
 820          lonAdvect_deg_r4 = real(lonAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 821          latAdvect_deg_r4 = real(latAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 822          ierr = gdxyfll(hco%EZscintID, xpos_r4, ypos_r4, &
 823               latAdvect_deg_r4, lonAdvect_deg_r4, 1)
 824          if (verbose) then
 825            write(*,*) 'new                            xpos_r4 > ni :', &
 826                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 827                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 828          end if
 829        end if
 830
 831        ! check if position is west of the grid
 832        if (floor(xpos_r4) < 1) then
 833          if (verbose) then
 834            write(*,*) 'lonIndex0,latIndex0,lon,lat,stepIndexSF,x,y xpos_r4 <  1 :', &
 835                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 836                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 837          end if
 838          ! subtract 10*epsilon(real*4) to ensure do not go too far due to limited precision
 839          lonAdvect = lonAdvect + 2.0D0*MPC_PI_R8 - 10.0D0*real(epsilon(1.0),8)
 840          lonAdvect_deg_r4 = real(lonAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 841          latAdvect_deg_r4 = real(latAdvect,4)* MPC_DEGREES_PER_RADIAN_R4
 842          ierr = gdxyfll(hco%EZscintID, xpos_r4, ypos_r4, &
 843               latAdvect_deg_r4, lonAdvect_deg_r4, 1)
 844          if (verbose) then
 845            write(*,*) 'new                            xpos_r4 <  1 :', &
 846                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 847                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 848          end if
 849        end if
 850
 851        ! longitude is still outside grid - should not happen!
 852        if (floor(xpos_r4) > ni) then 
 853          write(*,*) '***still outside lonIndex > ni: stepIndexSF,subStepIndex,lonIndex0,latIndex0,x,y,uu=', &
 854               stepIndexSF,subStepIndex,lonIndex0,latIndex0,xpos_r4,ypos_r4,uu
 855          xpos_r4 = real(ni)
 856          lonAdvect = hco%lon(ni)
 857        end if
 858        if (floor(xpos_r4) <  1) then 
 859          write(*,*) '***still outside lonIndex < 1 : stepIndexSF,subStepIndex,lonIndex0,latIndex0,x,y,uu=', &
 860               stepIndexSF,subStepIndex,lonIndex0,latIndex0,xpos_r4,ypos_r4,uu
 861          xpos_r4 = 1.0
 862          lonAdvect = hco%lon(1)
 863        end if
 864
 865        ! if position is poleward of last lat circle, ensure valid lat index
 866        if (latIndex > nj) then
 867          if (verbose) then
 868            write(*,*) 'lonIndex0,latIndex0,lon,lat,stepIndexSF,x,y ypos_r4 > nj :', &
 869                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 870                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 871          end if
 872          ypos_r4 = real(nj)
 873          latAdvect = hco%lat(nj)
 874        end if
 875
 876        ! if position is poleward of first lat circle, ensure valid lat index
 877        if (latIndex < 1) then
 878          if (verbose) then
 879            write(*,*) 'lonIndex0,latIndex0,lon,lat,stepIndexSF,x,y ypos_r4 <  1 :', &
 880                 lonIndex0,latIndex0,lonAdvect*MPC_DEGREES_PER_RADIAN_R8, &
 881                 latAdvect*MPC_DEGREES_PER_RADIAN_R8,stepIndexSF,xpos_r4,ypos_r4
 882          end if
 883          ypos_r4 = 1.0
 884          latAdvect = hco%lat(1)
 885        end if
 886
 887        ! determine bottom left grid point again after possible adjustments
 888        lonIndex = floor(xpos_r4)
 889        latIndex = floor(ypos_r4)
 890
 891      end do ! subStepIndex
 892
 893    end do ! stepIndexSF
 894
 895    if (verbose) write(*,*) 'final, initial xpos,ypos', lonIndex0,latIndex0,xpos_r4, ypos_r4
 896
 897  end SUBROUTINE calcTrajectory
 898  
 899  !--------------------------------------------------------------------------
 900  ! calcWeights
 901  !--------------------------------------------------------------------------
 902  SUBROUTINE calcWeights(lonIndex, latIndex, interpWeight_BL, interpWeight_BR, &
 903                         interpWeight_TL, interpWeight_TR, xpos_r4, ypos_r4)
 904    implicit none
 905
 906    ! Arguments:
 907    integer, intent(out) :: lonIndex
 908    integer, intent(out) :: latIndex
 909    real(8), intent(out) :: interpWeight_BL
 910    real(8), intent(out) :: interpWeight_BR
 911    real(8), intent(out) :: interpWeight_TL
 912    real(8), intent(out) :: interpWeight_TR
 913    real(4), intent(in)  :: xpos_r4
 914    real(4), intent(in)  :: ypos_r4
 915
 916    ! Locals:
 917    real(8) :: delx, dely, sumWeight
 918
 919    ! Determine bottom left grid point
 920    lonIndex = floor(xpos_r4)
 921    latIndex = floor(ypos_r4)
 922
 923    if (lonIndex < 1 .or. lonIndex > hco%ni .or. &
 924        latIndex < 1 .or. latIndex > hco%nj ) then
 925      write(*,*)
 926      write(*,*) 'calcWeights: the input positions are wrong'
 927      write(*,*) '             xpos_r4, ypos_r4, lonIndex, latIndex = ', xpos_r4, ypos_r4, lonIndex, latIndex
 928      call utl_abort('calcWeights')
 929    end if
 930
 931    ! Compute the surrounding four gridpoint interpolation weights
 932    delx = real(xpos_r4,8) - real(lonIndex,8)
 933    dely = real(ypos_r4,8) - real(latIndex,8)
 934
 935    interpWeight_BL = min(max( (1.d0-delx) * (1.d0-dely), 0.0d0), 1.0d0)
 936    interpWeight_BR = min(max(       delx  * (1.d0-dely), 0.0d0), 1.0d0)
 937    interpWeight_TL = min(max( (1.d0-delx) *       dely , 0.0d0), 1.0d0)
 938    interpWeight_TR = min(max(       delx  *       dely , 0.0d0), 1.0d0)
 939
 940    ! Verification
 941    sumWeight = interpWeight_BL + interpWeight_BR + interpWeight_TL +  interpWeight_TR
 942
 943    if (sumWeight > 1.0d0) then
 944      write(*,*) 'sumWeight > 1.0 : ', sumWeight
 945      write(*,*) '          BL, BR, TL, TR=', &
 946           interpWeight_BL, interpWeight_BR, interpWeight_TL, interpWeight_TR
 947      write(*,*) '          xpos_r4, ypos_r4, lonIndex, latIndex, delx, dely  =', &
 948           xpos_r4, ypos_r4, lonIndex, latIndex, delx, dely
 949      call utl_abort('calcWeights')
 950    end if
 951
 952  end SUBROUTINE calcWeights
 953
 954  !--------------------------------------------------------------------------
 955  ! adv_ensemble_tl
 956  !--------------------------------------------------------------------------
 957  SUBROUTINE adv_ensemble_tl( ens, adv, nEns )
 958    implicit none
 959
 960    ! Arguments:
 961    type(struct_ens), intent(inout) :: ens
 962    type(struct_adv), intent(in)    :: adv
 963    integer,          intent(in)    :: nEns
 964
 965    if ( adv%nLev_M /= ens_getNumLev(ens,'MM') .or. adv%nLev_T /= ens_getNumLev(ens,'TH') ) then
 966      call utl_abort('adv_ensemble_tl: vertical levels are not compatible')
 967    end if
 968
 969    if      ( ens_getDataKind(ens) == 8 ) then
 970      call adv_ensemble_tl_r8( ens, adv, nEns )
 971    else if ( ens_getDataKind(ens) == 4 ) then
 972      call adv_ensemble_tl_r4( ens, adv, nEns )
 973    else
 974      call utl_abort('adv_ensemble_tl: ens%dataKind not valid')
 975    end if
 976
 977  END SUBROUTINE adv_ensemble_tl
 978
 979  !--------------------------------------------------------------------------
 980  ! adv_ensemble_tl_r8
 981  !--------------------------------------------------------------------------
 982  SUBROUTINE adv_ensemble_tl_r8( ens, adv, nEns )
 983    implicit none
 984
 985    ! Arguments:
 986    type(struct_ens), intent(inout) :: ens
 987    type(struct_adv), intent(in)    :: adv
 988    integer,          intent(in)    :: nEns
 989
 990    ! Locals:
 991    real(8), pointer     :: ens_oneLev(:,:,:,:)
 992    real(8), allocatable :: ens1_mpiglobal_tiles(:,:,:,:)
 993    real(8), allocatable :: ens1_mpiglobal(:,:,:)
 994    integer :: memberIndex, levIndex, lonIndex, latIndex, kIndex
 995    integer :: lonIndex2, latIndex2, lonIndex2_p1, latIndex2_p1, nsize, ierr
 996    integer :: procID, procIDx, procIDy, lonIndex_mpiglobal, latIndex_mpiglobal
 997    integer :: levTypeIndex, stepIndexAF
 998    logical :: gatheringDone
 999    character(len=4) :: varName
1000
1001    allocate(ens1_mpiglobal_tiles(nEns,adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1002    allocate(ens1_mpiglobal(nEns,adv%ni,adv%nj))
1003
1004    do kIndex = 1, ens_getNumK(ens)
1005
1006      levIndex = ens_getLevFromK    (ens,kIndex)
1007      varName  = ens_getVarNameFromK(ens,kIndex)
1008      if      (vnl_varLevelFromVarname(varName) == 'MM') then
1009        levTypeIndex = MMindex
1010      else if (vnl_varLevelFromVarname(varName) == 'TH') then
1011        levTypeIndex = THindex
1012      else if (vnl_varLevelFromVarname(varName) == 'SF') then
1013        levTypeIndex = SFindex
1014      end if
1015
1016      ens_oneLev => ens_getOneLev_r8(ens,kIndex)
1017
1018      gatheringDone = .false.
1019
1020      do stepIndexAF = 1, adv%nTimeStep
1021
1022        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
1023
1024        if (.not. gatheringDone ) then
1025
1026          ! gather the global field to be interpolated on all tasks
1027          nsize = nEns*adv%lonPerPE*adv%latPerPE
1028          call rpn_comm_allgather(ens_oneLev(1:nEns,adv%timeStepIndexSource(stepIndexAF),:,:), nsize, "mpi_double_precision",  &
1029                                  ens1_mpiglobal_tiles(:,:,:,:), nsize, "mpi_double_precision",  &
1030                                  "GRID", ierr )
1031
1032          ! rearrange gathered fields for convenience
1033          !$OMP PARALLEL DO PRIVATE (procIDy,procIDx,procID,latIndex,lonIndex,latIndex_mpiglobal,lonIndex_mpiglobal,memberIndex)
1034          do procIDy = 0, (mmpi_npey-1)
1035            do procIDx = 0, (mmpi_npex-1)
1036              procID = procIDx + procIDy*mmpi_npex
1037              do latIndex = 1, adv%latPerPE
1038                latIndex_mpiglobal = latIndex + adv%allLatBeg(procIDy+1) - 1
1039                do lonIndex = 1, adv%lonPerPE
1040                  lonIndex_mpiglobal = lonIndex + adv%allLonBeg(procIDx+1) - 1
1041                  do memberIndex = 1, nEns
1042                    ens1_mpiglobal(memberIndex,lonIndex_mpiglobal, latIndex_mpiglobal) = &
1043                         ens1_mpiglobal_tiles(memberIndex, lonIndex, latIndex, procID+1)
1044                  end do ! memberIndex
1045                end do ! lonIndex
1046              end do ! latIndex
1047            end do ! procIDx
1048          end do ! procIDy
1049          !$OMP END PARALLEL DO
1050
1051          if (adv%singleTimeStepIndexSource) gatheringDone = .true.
1052
1053        end if
1054
1055        !$OMP PARALLEL DO PRIVATE (latIndex,lonIndex,lonIndex2,latIndex2,lonIndex2_p1,latIndex2_p1,memberIndex)
1056        do latIndex = adv%myLatBeg, adv%myLatEnd
1057          do lonIndex = adv%myLonBeg, adv%myLonEnd
1058            lonIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex(lonIndex,latIndex,levIndex)
1059            latIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex(lonIndex,latIndex,levIndex)
1060            lonIndex2_p1 = mod(lonIndex2,adv%ni)+1 ! assume periodic
1061            latIndex2_p1 = min(latIndex2+1,adv%nj)
1062            do memberIndex = 1, nEns
1063              ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex) =                                           &
1064                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex,latIndex,levIndex)* &
1065                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2   ) +                                 &
1066                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex,latIndex,levIndex)* &
1067                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2   ) +                                 &
1068                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex,latIndex,levIndex)* &
1069                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2_p1) +                                 &
1070                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex,latIndex,levIndex)* &
1071                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2_p1)
1072            end do ! memberIndex
1073          end do ! lonIndex
1074        end do ! latIndex
1075        !$OMP END PARALLEL DO
1076
1077      end do ! stepIndexAF
1078      
1079    end do ! kIndex
1080
1081    deallocate(ens1_mpiglobal_tiles)
1082    deallocate(ens1_mpiglobal)
1083
1084  END SUBROUTINE adv_ensemble_tl_r8
1085
1086  !--------------------------------------------------------------------------
1087  ! adv_ensemble_tl_r8
1088  !--------------------------------------------------------------------------
1089  SUBROUTINE adv_ensemble_tl_r4( ens, adv, nEns )
1090    implicit none
1091
1092    ! Arguments:
1093    type(struct_ens), intent(inout) :: ens
1094    type(struct_adv), intent(in)    :: adv
1095    integer,          intent(in)    :: nEns
1096
1097    ! Locals:
1098    real(4), pointer     :: ens_oneLev(:,:,:,:)
1099    real(4), allocatable :: ens1_mpiglobal_tiles(:,:,:,:)
1100    real(4), allocatable :: ens1_mpiglobal(:,:,:)
1101    integer :: memberIndex, levIndex, lonIndex, latIndex, kIndex
1102    integer :: lonIndex2, latIndex2, lonIndex2_p1, latIndex2_p1, nsize, ierr
1103    integer :: procID, procIDx, procIDy, lonIndex_mpiglobal, latIndex_mpiglobal
1104    integer :: levTypeIndex, stepIndexAF
1105    logical :: gatheringDone
1106    character(len=4) :: varName
1107
1108    allocate(ens1_mpiglobal_tiles(nEns,adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1109    allocate(ens1_mpiglobal(nEns,adv%ni,adv%nj))
1110
1111    do kIndex = 1, ens_getNumK(ens)
1112
1113      levIndex = ens_getLevFromK    (ens,kIndex)
1114      varName  = ens_getVarNameFromK(ens,kIndex)
1115      if      (vnl_varLevelFromVarname(varName) == 'MM') then
1116        levTypeIndex = MMindex
1117      else if (vnl_varLevelFromVarname(varName) == 'TH') then
1118        levTypeIndex = THindex
1119      else if (vnl_varLevelFromVarname(varName) == 'SF') then
1120        levTypeIndex = SFindex
1121      end if
1122
1123      ens_oneLev => ens_getOneLev_r4(ens,kIndex)
1124
1125      gatheringDone = .false.
1126
1127      do stepIndexAF = 1, adv%nTimeStep
1128
1129        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
1130
1131        if (.not. gatheringDone ) then
1132
1133          ! gather the global field to be interpolated on all tasks
1134          nsize = nEns*adv%lonPerPE*adv%latPerPE
1135          call rpn_comm_allgather(ens_oneLev(1:nEns,adv%timeStepIndexSource(stepIndexAF),:,:), nsize, "mpi_real4",  &
1136                                  ens1_mpiglobal_tiles(:,:,:,:), nsize, "mpi_real4",  &
1137                                  "GRID", ierr )
1138
1139          ! rearrange gathered fields for convenience
1140          !$OMP PARALLEL DO PRIVATE (procIDy,procIDx,procID,latIndex,lonIndex,latIndex_mpiglobal,lonIndex_mpiglobal,memberIndex)
1141          do procIDy = 0, (mmpi_npey-1)
1142            do procIDx = 0, (mmpi_npex-1)
1143              procID = procIDx + procIDy*mmpi_npex
1144              do latIndex = 1, adv%latPerPE
1145                latIndex_mpiglobal = latIndex + adv%allLatBeg(procIDy+1) - 1
1146                do lonIndex = 1, adv%lonPerPE
1147                  lonIndex_mpiglobal = lonIndex + adv%allLonBeg(procIDx+1) - 1
1148                  do memberIndex = 1, nEns
1149                    ens1_mpiglobal(memberIndex,lonIndex_mpiglobal, latIndex_mpiglobal) = &
1150                         ens1_mpiglobal_tiles(memberIndex, lonIndex, latIndex, procID+1)
1151                  end do ! memberIndex
1152                end do ! lonIndex
1153              end do ! latIndex
1154            end do ! procIDx
1155          end do ! procIDy
1156          !$OMP END PARALLEL DO
1157
1158          if (adv%singleTimeStepIndexSource) gatheringDone = .true. 
1159
1160        end if
1161
1162        !$OMP PARALLEL DO PRIVATE (latIndex,lonIndex,lonIndex2,latIndex2,lonIndex2_p1,latIndex2_p1,memberIndex)
1163        do latIndex = adv%myLatBeg, adv%myLatEnd
1164          do lonIndex = adv%myLonBeg, adv%myLonEnd
1165            lonIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex(lonIndex,latIndex,levIndex)
1166            latIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex(lonIndex,latIndex,levIndex)
1167            lonIndex2_p1 = mod(lonIndex2,adv%ni)+1 ! assume periodic
1168            latIndex2_p1 = min(latIndex2+1,adv%nj)
1169            do memberIndex = 1, nEns
1170              ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex) =                                           &
1171                   real(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex,latIndex,levIndex),4)* &
1172                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2   ) +                                 &
1173                   real(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex,latIndex,levIndex),4)* &
1174                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2   ) +                                 &
1175                   real(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex,latIndex,levIndex),4)* &
1176                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2_p1) +                                 &
1177                   real(adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex,latIndex,levIndex),4)* &
1178                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2_p1)
1179            end do ! memberIndex
1180          end do ! lonIndex
1181        end do ! latIndex
1182        !$OMP END PARALLEL DO
1183
1184      end do ! stepIndexAF
1185      
1186    end do ! kIndex
1187
1188    deallocate(ens1_mpiglobal_tiles)
1189    deallocate(ens1_mpiglobal)
1190
1191  END SUBROUTINE adv_ensemble_tl_r4
1192
1193  !--------------------------------------------------------------------------
1194  ! adv_ensemble_ad
1195  !--------------------------------------------------------------------------
1196  SUBROUTINE adv_ensemble_ad( ens, adv, nEns )
1197    implicit none
1198
1199    ! Arguments:
1200    type(struct_ens), intent(inout) :: ens
1201    type(struct_adv), intent(in)    :: adv
1202    integer,          intent(in)    :: nEns
1203
1204    ! Locals:
1205    real(8), pointer     :: ens_oneLev(:,:,:,:)
1206    real(8), allocatable :: ens1_mpiglobal(:,:,:)
1207    real(8), allocatable :: ens1_mpiglobal_tiles(:,:,:,:)
1208    real(8), allocatable :: ens1_mpiglobal_tiles2(:,:,:,:)
1209    integer :: memberIndex, levIndex, lonIndex, latIndex, kIndex
1210    integer :: lonIndex2, latIndex2, lonIndex2_p1, latIndex2_p1, nsize, ierr
1211    integer :: procID, procIDx, procIDy, lonIndex_mpiglobal, latIndex_mpiglobal
1212    integer :: levTypeIndex, stepIndexAF
1213    character(len=4) :: varName
1214
1215    if ( .not. adv%singleTimeStepIndexSource ) then
1216      call utl_abort('adv_ensemble_ad cannot deal with multiple timeStep index source')
1217    end if
1218    if ( ens_getDataKind(ens) /= 8 ) then
1219      call utl_abort('adv_ensemble_ad can only deal with double precision (real8) ensembleStateVector')
1220    end if
1221    if ( adv%nLev_M /= ens_getNumLev(ens,'MM') .or. adv%nLev_T /= ens_getNumLev(ens,'TH') ) then
1222      call utl_abort('adv_ensemble_ad: vertical levels are not compatible')
1223    end if
1224    if ( .not. nlat_equalAcrossMpiTasks .or. .not. nlon_equalAcrossMpiTasks) then
1225      call utl_abort('adv_ensemble_ad can only deal with even nlon and nlat across all MPI tasks')
1226    end if
1227
1228    allocate(ens1_mpiglobal(nEns,adv%ni,adv%nj))
1229    allocate(ens1_mpiglobal_tiles (nEns,adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1230    allocate(ens1_mpiglobal_tiles2(nEns,adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1231
1232    do kIndex = 1, ens_getNumK(ens)
1233            
1234      levIndex = ens_getLevFromK    (ens,kIndex)
1235      varName  = ens_getVarNameFromK(ens,kIndex)
1236      if      (vnl_varLevelFromVarname(varName) == 'MM') then
1237        levTypeIndex = MMindex
1238      else if (vnl_varLevelFromVarname(varName) == 'TH') then
1239        levTypeIndex = THindex
1240      else if (vnl_varLevelFromVarname(varName) == 'SF') then
1241        levTypeIndex = SFindex
1242      end if
1243
1244      ens1_mpiglobal(:,:,:) = 0.0d0
1245      ens_oneLev => ens_getOneLev_r8(ens,kIndex)
1246
1247      do latIndex = adv%myLatBeg, adv%myLatEnd
1248        do lonIndex = adv%myLonBeg, adv%myLonEnd
1249          do stepIndexAF = 1, adv%nTimeStep
1250            if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
1251            ! this is the bottom-left grid point
1252            lonIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex(lonIndex,latIndex,levIndex)
1253            latIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex(lonIndex,latIndex,levIndex)
1254            lonIndex2_p1 = mod(lonIndex2,adv%ni)+1 ! assume periodic
1255            latIndex2_p1 = min(latIndex2+1,adv%nj)
1256            !$OMP PARALLEL DO PRIVATE(memberIndex)
1257            do memberIndex = 1, nEns
1258              ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2) = &
1259                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2) +  &
1260                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex,latIndex,levIndex)* &
1261                      ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex)
1262              ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2) = &
1263                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2) +  &
1264                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex,latIndex,levIndex)* &
1265                      ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex)
1266              ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2_p1) = &
1267                   ens1_mpiglobal(memberIndex, lonIndex2   ,latIndex2_p1) +  &
1268                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex,latIndex,levIndex)* &
1269                      ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex)
1270              ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2_p1) = &
1271                   ens1_mpiglobal(memberIndex, lonIndex2_p1,latIndex2_p1) +  &
1272                   adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex,latIndex,levIndex)* &
1273                      ens_oneLev(memberIndex,stepIndexAF,lonIndex,latIndex)
1274            end do ! memberIndex
1275            !$OMP END PARALLEL DO
1276          end do ! stepIndexAF
1277        end do ! lonIndex
1278      end do ! latIndex
1279
1280      ! redistribute the global initial time field across mpi tasks by tiles
1281      !$OMP PARALLEL DO PRIVATE(procIDy,procIDx,procID,latIndex,latIndex_mpiglobal,lonIndex,lonIndex_mpiglobal,memberIndex)
1282      do procIDy = 0, (mmpi_npey-1)
1283        do procIDx = 0, (mmpi_npex-1)
1284          procID = procIDx + procIDy*mmpi_npex
1285          do latIndex = 1, adv%latPerPE
1286            latIndex_mpiglobal = latIndex + adv%allLatBeg(procIDy+1) - 1
1287            do lonIndex = 1, adv%lonPerPE
1288              lonIndex_mpiglobal = lonIndex + adv%allLonBeg(procIDx+1) - 1
1289              do memberIndex = 1, nEns
1290                ens1_mpiglobal_tiles(memberIndex, lonIndex, latIndex, procID+1) =  &
1291                     ens1_mpiglobal(memberIndex, lonIndex_mpiglobal, latIndex_mpiglobal)
1292              end do ! memberIndex
1293            end do ! lonIndex
1294          end do ! latIndex
1295        end do ! procIDx
1296      end do ! procIDy
1297      !$OMP END PARALLEL DO
1298
1299      nsize = nEns*adv%lonPerPE*adv%latPerPE
1300      if (mmpi_nprocs > 1) then
1301        call rpn_comm_alltoall(ens1_mpiglobal_tiles, nsize,"mpi_double_precision",  &
1302                               ens1_mpiglobal_tiles2,nsize,"mpi_double_precision","GRID",ierr)
1303      else
1304        ens1_mpiglobal_tiles2(:,:,:,1) = ens1_mpiglobal_tiles(:,:,:,1)
1305      end if
1306
1307      do procID = 0, (mmpi_nprocs-1)
1308        !$OMP PARALLEL DO PRIVATE(latIndex,latIndex2,lonIndex,lonIndex2,memberIndex)
1309        do latIndex = 1, adv%latPerPE
1310          latIndex2= latIndex + adv%myLatBeg - 1
1311          do lonIndex = 1, adv%lonPerPE
1312            lonIndex2 = lonIndex + adv%myLonBeg - 1
1313            do memberIndex = 1, nEns
1314              ens_oneLev(memberIndex, adv%timeStepIndexMainSource, lonIndex2, latIndex2) = &
1315                   ens_oneLev(memberIndex, adv%timeStepIndexMainSource, lonIndex2, latIndex2) +  &
1316                   ens1_mpiglobal_tiles2(memberIndex, lonIndex, latIndex, procID+1)
1317            end do ! memberIndex
1318          end do ! lonIndex
1319        end do ! latIndex
1320        !$OMP END PARALLEL DO
1321      end do ! procID
1322
1323    end do ! levIndex
1324
1325    deallocate(ens1_mpiglobal)
1326    deallocate(ens1_mpiglobal_tiles)
1327    deallocate(ens1_mpiglobal_tiles2)
1328
1329  END SUBROUTINE adv_ensemble_ad
1330
1331  !--------------------------------------------------------------------------
1332  ! adv_statevector_tl
1333  !--------------------------------------------------------------------------
1334  SUBROUTINE adv_statevector_tl( statevector, adv)
1335    implicit none
1336
1337    ! Arguments:
1338    type(struct_gsv), intent(inout) :: statevector
1339    type(struct_adv), intent(in)    :: adv
1340
1341    ! Locals:
1342    real(8), pointer     :: field4D(:,:,:,:)
1343    real(8), allocatable :: field2D_mpiglobal_tiles(:,:,:)
1344    real(8), allocatable :: field2D_mpiglobal(:,:)
1345    integer :: levIndex, lonIndex, latIndex, kIndex
1346    integer :: lonIndex2, latIndex2, lonIndex2_p1, latIndex2_p1, nsize, ierr
1347    integer :: procID, procIDx, procIDy, lonIndex_mpiglobal, latIndex_mpiglobal
1348    integer :: levTypeIndex, stepIndexAF
1349    logical :: gatheringDone
1350    character(len=4) :: varName
1351
1352    if ( gsv_getDataKind(statevector) /= 8 ) then
1353      call utl_abort('adv_statevector_tl can only deal with double precision (real8) gridStateVector')
1354    end if
1355    if ( adv%nLev_M /= statevector%vco%nLev_M .or. adv%nLev_T /= statevector%vco%nLev_T ) then
1356      call utl_abort('adv_statevector_tl: vertical levels are not compatible')
1357    end if
1358
1359    call utl_tmg_start(100,'--ADV_GSV')
1360
1361    allocate(field2D_mpiglobal_tiles(adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1362    allocate(field2D_mpiglobal(adv%ni,adv%nj))
1363
1364    do kIndex = 1, gsv_getNumK(statevector)
1365
1366      levIndex = gsv_getLevFromK    (statevector,kIndex)
1367      varName  = gsv_getVarNameFromK(statevector,kIndex)
1368      if      (vnl_varLevelFromVarname(varName) == 'MM') then
1369        levTypeIndex = MMindex
1370      else if (vnl_varLevelFromVarname(varName) == 'TH') then
1371        levTypeIndex = THindex
1372      else if (vnl_varLevelFromVarname(varName) == 'SF') then
1373        levTypeIndex = SFindex
1374      end if
1375
1376      call gsv_getField(statevector, field4D, varName)
1377
1378      gatheringDone = .false.
1379
1380      do stepIndexAF = 1, adv%nTimeStep
1381
1382        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
1383
1384        if (.not. gatheringDone ) then
1385
1386          ! gather the global field to be interpolated on all tasks
1387          call rpn_comm_barrier('GRID',ierr)
1388          call utl_tmg_start(101,'----ADV_GSV_Comm')
1389          nsize = adv%lonPerPE*adv%latPerPE
1390          call rpn_comm_allgather(field4D(:,:,levIndex,adv%timeStepIndexSource(stepIndexAF)), nsize, "mpi_double_precision",  &
1391                                  field2D_mpiglobal_tiles(:,:,:), nsize, "mpi_double_precision",  &
1392                                  "GRID", ierr )
1393          call utl_tmg_stop(101)
1394
1395          ! rearrange gathered fields for convenience
1396          call utl_tmg_start(102,'----ADV_GSV_Shuffling')
1397          !$OMP PARALLEL DO PRIVATE (procIDy,procIDx,procID,latIndex,lonIndex,latIndex_mpiglobal,lonIndex_mpiglobal)
1398          do procIDy = 0, (mmpi_npey-1)
1399            do procIDx = 0, (mmpi_npex-1)
1400              procID = procIDx + procIDy*mmpi_npex
1401              do latIndex = 1, adv%latPerPE
1402                latIndex_mpiglobal = latIndex + adv%allLatBeg(procIDy+1) - 1
1403                do lonIndex = 1, adv%lonPerPE
1404                  lonIndex_mpiglobal = lonIndex + adv%allLonBeg(procIDx+1) - 1
1405                    field2D_mpiglobal(lonIndex_mpiglobal, latIndex_mpiglobal) = &
1406                         field2D_mpiglobal_tiles(lonIndex, latIndex, procID+1)
1407                end do ! lonIndex
1408              end do ! latIndex
1409            end do ! procIDx
1410          end do ! procIDy
1411          !$OMP END PARALLEL DO
1412          call utl_tmg_stop(102)
1413
1414          if (adv%singleTimeStepIndexSource) gatheringDone = .true. 
1415
1416        end if
1417
1418        call utl_tmg_start(103,'----ADV_GSV_Calc')
1419
1420        !$OMP PARALLEL DO PRIVATE (latIndex,lonIndex,lonIndex2,latIndex2,lonIndex2_p1,latIndex2_p1)
1421        do latIndex = adv%myLatBeg, adv%myLatEnd
1422          do lonIndex = adv%myLonBeg, adv%myLonEnd
1423            lonIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex(lonIndex,latIndex,levIndex)
1424            latIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex(lonIndex,latIndex,levIndex)
1425            lonIndex2_p1 = mod(lonIndex2,adv%ni)+1 ! assume periodic
1426            latIndex2_p1 = min(latIndex2+1,adv%nj)
1427            field4D(lonIndex,latIndex,levIndex,stepIndexAF) =                                                 &
1428                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex,latIndex,levIndex)* &
1429                 field2D_mpiglobal(lonIndex2   ,latIndex2   ) +                                               &
1430                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex,latIndex,levIndex)* &
1431                 field2D_mpiglobal(lonIndex2_p1,latIndex2   ) +                                               &
1432                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex,latIndex,levIndex)* &
1433                 field2D_mpiglobal(lonIndex2   ,latIndex2_p1) +                                               &
1434                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex,latIndex,levIndex)* &
1435                 field2D_mpiglobal(lonIndex2_p1,latIndex2_p1)
1436          end do ! lonIndex
1437        end do ! latIndex
1438        !$OMP END PARALLEL DO
1439
1440        call utl_tmg_stop(103)
1441
1442      end do ! stepIndexAF
1443
1444    end do ! kIndex
1445
1446    deallocate(field2D_mpiglobal_tiles)
1447    deallocate(field2D_mpiglobal)
1448
1449    call utl_tmg_stop(100)
1450
1451  END SUBROUTINE adv_statevector_tl
1452
1453  !--------------------------------------------------------------------------
1454  ! adv_statevector_ad
1455  !--------------------------------------------------------------------------
1456  SUBROUTINE adv_statevector_ad( statevector, adv)
1457    implicit none
1458
1459    ! Arguments:
1460    type(struct_gsv), intent(inout) :: statevector
1461    type(struct_adv), intent(in)    :: adv
1462
1463    ! Locals:
1464    real(8), pointer     :: field4D(:,:,:,:)
1465    real(8), allocatable :: field2D_mpiglobal(:,:)
1466    real(8), allocatable :: field2D_mpiglobal_tiles (:,:,:)
1467    real(8), allocatable :: field2D_mpiglobal_tiles2(:,:,:)
1468    integer :: levIndex, lonIndex, latIndex, kIndex
1469    integer :: lonIndex2, latIndex2, lonIndex2_p1, latIndex2_p1, nsize, ierr
1470    integer :: procID, procIDx, procIDy, lonIndex_mpiglobal, latIndex_mpiglobal
1471    integer :: levTypeIndex, stepIndexAF
1472    character(len=4) :: varName
1473
1474    if ( adv%singleTimeStepIndexSource ) then
1475      call utl_abort('adv_statevector_ad cannot work for singleTimeStepIndexSource')
1476    end if
1477    if ( gsv_getDataKind(statevector) /= 8 ) then
1478      call utl_abort('adv_statevector_ad can only deal with double precision (real8) ensembleStateVector')
1479    end if
1480    if ( adv%nLev_M /= statevector%vco%nLev_M .or. adv%nLev_T /= statevector%vco%nLev_T ) then
1481      call utl_abort('adv_statevector_ad: vertical levels are not compatible')
1482    end if
1483    if ( .not. nlat_equalAcrossMpiTasks .or. .not. nlon_equalAcrossMpiTasks) then
1484      call utl_abort('adv_ensemble_ad can only deal with even nlon and nlat across all MPI tasks')
1485    end if
1486
1487    allocate(field2D_mpiglobal(adv%ni,adv%nj))
1488    allocate(field2D_mpiglobal_tiles (adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1489    allocate(field2D_mpiglobal_tiles2(adv%lonPerPE,adv%latPerPE,mmpi_nprocs))
1490
1491    do kIndex = 1, gsv_getNumK(statevector)
1492            
1493      levIndex = gsv_getLevFromK    (statevector,kIndex)
1494      varName  = gsv_getVarNameFromK(statevector,kIndex)
1495      if      (vnl_varLevelFromVarname(varName) == 'MM') then
1496        levTypeIndex = MMindex
1497      else if (vnl_varLevelFromVarname(varName) == 'TH') then
1498        levTypeIndex = THindex
1499      else if (vnl_varLevelFromVarname(varName) == 'SF') then
1500        levTypeIndex = SFindex
1501      end if
1502
1503      call gsv_getField(statevector, field4D, varName)
1504
1505      do stepIndexAF = 1, adv%nTimeStep
1506
1507        if (stepIndexAF == adv%timeStepIndexMainSource) cycle ! no interpolation needed for this time step
1508
1509        field2D_mpiglobal(:,:)                      = 0.0d0
1510
1511        do latIndex = adv%myLatBeg, adv%myLatEnd
1512          do lonIndex = adv%myLonBeg, adv%myLonEnd
1513            ! this is the bottom-left grid point
1514            lonIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%lonIndex(lonIndex,latIndex,levIndex)
1515            latIndex2 = adv%timeStep(stepIndexAF)%levType(levTypeIndex)%latIndex(lonIndex,latIndex,levIndex)
1516            lonIndex2_p1 = mod(lonIndex2,adv%ni)+1 ! assume periodic
1517            latIndex2_p1 = min(latIndex2+1,adv%nj)
1518            field2D_mpiglobal(lonIndex2   ,latIndex2) = &
1519                 field2D_mpiglobal(lonIndex2   ,latIndex2) +  &
1520                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BL(lonIndex,latIndex,levIndex)* &
1521                 field4D(lonIndex,latIndex,levIndex,stepIndexAF)
1522            field2D_mpiglobal(lonIndex2_p1,latIndex2) = &
1523                 field2D_mpiglobal(lonIndex2_p1,latIndex2) +  &
1524                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_BR(lonIndex,latIndex,levIndex)* &
1525                 field4D(lonIndex,latIndex,levIndex,stepIndexAF)
1526            field2D_mpiglobal(lonIndex2   ,latIndex2_p1) = &
1527                 field2D_mpiglobal(lonIndex2   ,latIndex2_p1) +  &
1528                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TL(lonIndex,latIndex,levIndex)* &
1529                 field4D(lonIndex,latIndex,levIndex,stepIndexAF)
1530            field2D_mpiglobal(lonIndex2_p1,latIndex2_p1) = &
1531                 field2D_mpiglobal(lonIndex2_p1,latIndex2_p1) +  &
1532                 adv%timeStep(stepIndexAF)%levType(levTypeIndex)%interpWeight_TR(lonIndex,latIndex,levIndex)* &
1533                 field4D(lonIndex,latIndex,levIndex,stepIndexAF)
1534          end do ! lonIndex
1535        end do ! latIndex
1536
1537        ! redistribute the global initial time field across mpi tasks by tiles
1538        !$OMP PARALLEL DO PRIVATE(procIDy,procIDx,procID,latIndex,latIndex_mpiglobal,lonIndex,lonIndex_mpiglobal)
1539        do procIDy = 0, (mmpi_npey-1)
1540          do procIDx = 0, (mmpi_npex-1)
1541            procID = procIDx + procIDy*mmpi_npex
1542            do latIndex = 1, adv%latPerPE
1543              latIndex_mpiglobal = latIndex + adv%allLatBeg(procIDy+1) - 1
1544              do lonIndex = 1, adv%lonPerPE
1545                lonIndex_mpiglobal = lonIndex + adv%allLonBeg(procIDx+1) - 1
1546                field2D_mpiglobal_tiles(lonIndex, latIndex, procID+1) =  &
1547                     field2D_mpiglobal(lonIndex_mpiglobal, latIndex_mpiglobal)
1548              end do ! lonIndex
1549            end do ! latIndex
1550          end do ! procIDx
1551        end do ! procIDy
1552        !$OMP END PARALLEL DO
1553
1554        nsize = adv%lonPerPE*adv%latPerPE
1555        if (mmpi_nprocs > 1) then
1556          call rpn_comm_alltoall(field2D_mpiglobal_tiles, nsize,"mpi_double_precision",  &
1557                                 field2D_mpiglobal_tiles2,nsize,"mpi_double_precision","GRID",ierr)
1558        else
1559          field2D_mpiglobal_tiles2(:,:,1) = field2D_mpiglobal_tiles(:,:,1)
1560        end if
1561
1562        field4D(:, :, levIndex, adv%timeStepIndexSource(stepIndexAF)) = 0.d0
1563
1564        do procID = 0, (mmpi_nprocs-1)
1565          !$OMP PARALLEL DO PRIVATE(latIndex,latIndex2,lonIndex,lonIndex2)
1566          do latIndex = 1, adv%latPerPE
1567            latIndex2= latIndex + adv%myLatBeg - 1
1568            do lonIndex = 1, adv%lonPerPE
1569              lonIndex2 = lonIndex + adv%myLonBeg - 1
1570              field4D(lonIndex2, latIndex2, levIndex, adv%timeStepIndexSource(stepIndexAF)) = &
1571                   field4D(lonIndex2, latIndex2, levIndex, adv%timeStepIndexSource(stepIndexAF)) + &
1572                   field2D_mpiglobal_tiles2(lonIndex, latIndex, procID+1)
1573            end do ! lonIndex
1574          end do ! latIndex
1575          !$OMP END PARALLEL DO
1576        end do ! procID
1577
1578      end do ! stepIndexAF
1579
1580    end do ! levIndex
1581
1582    deallocate(field2D_mpiglobal)
1583    deallocate(field2D_mpiglobal_tiles)
1584    deallocate(field2D_mpiglobal_tiles2)
1585
1586  END SUBROUTINE adv_statevector_ad
1587
1588END MODULE advection_mod