!--------------------------------------- LICENCE BEGIN -----------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------



subroutine checkObsMpiIP(lobsSpaceData,burp_split_L) 1,34
  !
  ! PURPOSE:
  !  check if all observations are correctly distributed along latitude bands
  !  if an observations is not, then don't assimilate this observation
  !
  use MathPhysConstants_mod
  use obsSpaceData_mod
  use HorizontalCoord_mod
  use MathPhysConstants_mod, only: MPC_DEGREES_PER_RADIAN_R4
  use mpivar_mod !! for variable 'mpi_myid'
  implicit none

  type(struct_obs), intent(inout) :: lobsSpaceData
  logical, intent(in) :: burp_split_L
  
  type(struct_hco), pointer :: hco_anl

  real(8) :: epsilon_lat,delta_lat,epsilon_lon,delta_lon
  real(8) :: lat_r8, lon_r8

  real    :: lat_r4, lon_r4
  real    :: xpos_r4, ypos_r4

  integer :: headerIndex
  integer :: latIndex, lonIndex
  integer :: ierr
  integer :: IP, IP_x, IP_y, count_obs_in
  integer :: idata,idatend,jdata
  integer :: gdxyfll

  write(*,*) 'routine checkObsMpiIP: numHeader = ',obs_numheader(lobsSpaceData)

  if (burp_split_L) then

     ! set tolerance on distance in radians from latitude band
     hco_anl => hco_Get('Analysis')
     epsilon_lat= abs(hco_anl % lat(1) - hco_anl % lat(2)) * 1.0d-4
     epsilon_lon= abs(hco_anl % lon(1) - hco_anl % lon(2)) * 1.0d-4
     write(*,*) 'routine checkObsMpiIP: epsilon_lat,_lon = ',epsilon_lat,epsilon_lon

     count_obs_in = 0
     do headerIndex = 1, obs_numheader(lobsSpaceData)

        lat_r8 = obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)
        lon_r8 = obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)
        lat_r4 = real(lat_r8) * MPC_DEGREES_PER_RADIAN_R4
        lon_r4 = real(lon_r8) * MPC_DEGREES_PER_RADIAN_R4
        ierr = gdxyfll( hco_anl % EZscintID, & ! IN 
                        xpos_r4, ypos_r4,    & ! OUT
                        lat_r4, lon_r4, 1 )    ! IN
        if ( trim(hco_anl % grtyp) == 'G' .and. hco_anl % ig2 == 1 ) then
          ! Revert latitudes since gdxyfll does not handle properly this grid type
          ypos_r4 = real(hco_anl % nj,4) - ypos_r4 + 1.0
        end if
        latIndex = floor(ypos_r4)
        lonIndex = floor(xpos_r4)
        IP_y = ( mpi_npey * (latIndex-1) ) / hco_anl%nj
        IP_x = ( mpi_npex * (lonIndex-1) ) / hco_anl%ni
        IP = IP_x + IP_y*mpi_npex

        ! obs outside lat-lon tile, first check if only epsilon_lat away from latitude band
        if ( IP .ne. mpi_myid ) then

           write(*,*) 'checkObsMpiIP: obs outside lat-lon tile, will check to see by how much'
           write(*,*) 'checkObsMpiIP: IP_x , IP_y , IP   = ', IP_x, IP_y, IP
           write(*,*) 'checkObsMpiIP: myidx, myidy, myid = ', mpi_myidx, mpi_myidy, mpi_myid
           write(*,*) 'checkObsMpiIP: obs lon       =',obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
           lonIndex = 1 + (mpi_myidx * hco_anl % ni / mpi_npex)
           write(*,*) 'checkObsMpiIP: tile lon west =',hco_anl % lon(lonIndex) * MPC_DEGREES_PER_RADIAN_R8
           lonIndex = 1 + ((mpi_myidx+1) * hco_anl % ni / mpi_npex)
           write(*,*) 'checkObsMpiIP: tile lon east =',hco_anl % lon(lonIndex) * MPC_DEGREES_PER_RADIAN_R8

           write(*,*) 'checkObsMpiIP: obs lat        =',obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
           if(mpi_myidy.gt.0) then
             latIndex = 1 + (mpi_myidy * hco_anl % nj / mpi_npey)
             write(*,*) 'checkObsMpiIP: tile lat north =',hco_anl % lat(latIndex) * MPC_DEGREES_PER_RADIAN_R8
           endif
           if(mpi_myidy.lt.(mpi_npey-1)) then
             latIndex = 1 + ((mpi_myidy+1) * hco_anl % nj / mpi_npey)
             write(*,*) 'checkObsMpiIP: tile lat south =',hco_anl % lat(latIndex) * MPC_DEGREES_PER_RADIAN_R8
           endif
           write(*,*) 'checkObsMpiIP: now checking...'

           ! for obs west of the correct longitude band
           lonIndex = 1 + (mpi_myidx * hco_anl % ni / mpi_npex)
           delta_lon=obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex) - hco_anl % lon(lonindex)
           if(IP_x .lt. mpi_myidx) then
              if(abs(delta_lon) .lt. epsilon_lon) then
                 ! obs kept and will be moved to the western boundary
                 write(*,*) 'checkObsMpiIP: keeping obs, will be moved to western boundary, headerIndex=',headerIndex
                 write(*,*) 'checkObsMpiIP: original lon=',obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: modified lon=',hco_anl % lon(lonindex) * MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: delta_lon   =',delta_lon*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: epsilon_lon =',epsilon_lon*MPC_DEGREES_PER_RADIAN_R8
                 IP = mpi_myid
              else
                 ! obs will be rejected, alert the user
                 write(*,*) 'checkObsMpiIP: removing obs, too far west of the correct longitude band, headerIndex=',headerIndex
                 write(*,*) 'checkObsMpiIP: original lon=',obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: boundary lon=',hco_anl % lon(lonIndex) * MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: assigned PE and PE_x, my PE and PE_x =',IP,IP_x,mpi_myid,mpi_myidx
                 write(*,*) 'checkObsMpiIP: delta_lon   =',delta_lon*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: epsilon_lon =',epsilon_lon*MPC_DEGREES_PER_RADIAN_R8
              endif
           endif

           ! for obs east of the correct longitude band
           lonIndex = 1 + ((mpi_myidx+1) * hco_anl % ni / mpi_npex)
           delta_lon=obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex) - hco_anl % lon(lonindex)
           if(IP_x .gt. mpi_myidx) then
              if(abs(delta_lon) .lt. epsilon_lon) then
                 ! obs kept and will be moved to the eastern boundary
                 write(*,*) 'checkObsMpiIP: keeping obs, will be moved to eastern boundary, headerIndex=',headerIndex
                 write(*,*) 'checkObsMpiIP: original lon=',obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: modified lon=',hco_anl % lon(lonindex) * MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: delta_lon   =',delta_lon*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: epsilon_lon =',epsilon_lon*MPC_DEGREES_PER_RADIAN_R8
                 IP = mpi_myid
              else
                 ! obs will be rejected, alert the user
                 write(*,*) 'checkObsMpiIP: removing obs, too far west of the correct longitude band, headerIndex=',headerIndex
                 write(*,*) 'checkObsMpiIP: original lon=',obs_headElem_r(lobsSpaceData,OBS_LON,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: boundary lon=',hco_anl % lon(lonIndex) * MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: assigned PE and PE_x, my PE and PE_x =',IP,IP_x,mpi_myid,mpi_myidx
                 write(*,*) 'checkObsMpiIP: delta_lon   =',delta_lon*MPC_DEGREES_PER_RADIAN_R8
                 write(*,*) 'checkObsMpiIP: epsilon_lon =',epsilon_lon*MPC_DEGREES_PER_RADIAN_R8
              endif
           endif

           ! for obs north of the correct latitude band
           if ( mpi_myidy .gt. 0 ) then ! ignore north pole
              latIndex = 1 + (mpi_myidy * hco_anl % nj / mpi_npey)
              delta_lat=obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex) - hco_anl % lat(latindex)
              if(IP_y .lt. mpi_myidy) then
                 if(abs(delta_lat) .lt. epsilon_lat) then
                    ! obs kept and will be moved to the northern boundary
                    write(*,*) 'checkObsMpiIP: keeping obs, will be moved to northern boundary, headerIndex=',headerIndex
                    write(*,*) 'checkObsMpiIP: original lat=',obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: modified lat=',hco_anl % lat(latindex) * MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: delta_lat   =',delta_lat*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: epsilon_lat =',epsilon_lat*MPC_DEGREES_PER_RADIAN_R8
                    IP = mpi_myid
                 else
                    ! obs will be rejected, alert the user
                    write(*,*) 'checkObsMpiIP: removing obs, too far north of the correct latitude band, headerIndex=',headerIndex
                    write(*,*) 'checkObsMpiIP: original lat=',obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: boundary lat=',hco_anl % lat(latindex) * MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: assigned PE and PE_y, my PE and PE_y =',IP,IP_y,mpi_myid,mpi_myidy
                    write(*,*) 'checkObsMpiIP: delta_lat   =',delta_lat*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: epsilon_lat =',epsilon_lat*MPC_DEGREES_PER_RADIAN_R8
                 endif
              endif
           endif
      
           ! for obs south of the correct latitude band
           if ( mpi_myidy .lt. (mpi_npey-1) ) then ! ignore south pole
              latindex = 1 + ((mpi_myidy+1)*hco_anl % nj / mpi_npey)
              delta_lat=obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex) - hco_anl % lat(latindex)
              if(IP_y .gt. mpi_myidy) then
                 if(abs(delta_lat) .lt. epsilon_lat) then
                    ! obs kept and will be moved to the southern boundary
                    write(*,*) 'checkObsMpiIP: keeping obs, will be moved to southern boundary, headerIndex=',headerIndex
                    write(*,*) 'checkObsMpiIP: original lat=',obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: modified lat=',hco_anl % lat(latindex) * MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: delta_lat   =',delta_lat*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: epsilon_lat =',epsilon_lat*MPC_DEGREES_PER_RADIAN_R8
                    IP = mpi_myid
                 else
                    ! obs will be rejected, alert the user
                    write(*,*) 'checkObsMpiIP: removing obs, too far south of the correct latitude band, headerIndex=',headerIndex
                    write(*,*) 'checkObsMpiIP: original lat=',obs_headElem_r(lobsSpaceData,OBS_LAT,headerIndex)*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: boundary lat=',hco_anl % lat(latindex) * MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: assigned PE and PE_y, my PE and PE_y =',IP,IP_y,mpi_myid,mpi_myidy
                    write(*,*) 'checkObsMpiIP: delta_lat   =',delta_lat*MPC_DEGREES_PER_RADIAN_R8
                    write(*,*) 'checkObsMpiIP: epsilon_lat =',epsilon_lat*MPC_DEGREES_PER_RADIAN_R8
                 endif
              endif
           endif
        endif

        ! now filter out obs still outside latitude band
        if ( IP .ne. mpi_myid ) then
           idata = obs_headElem_i(lobsSpaceData,OBS_RLN,headerIndex)
           idatend = obs_headElem_i(lobsSpaceData,OBS_NLV,headerIndex) + idata -1
           do jdata = idata, idatend
              call obs_bodySet_i(lobsSpaceData,OBS_ASS,JDATA, 0)
           enddo
           call obs_headSet_i(lobsSpaceData,OBS_ST1,headerIndex,  &
                ibset( obs_headElem_i(lobsSpaceData,OBS_ST1,headerIndex), 05))
        else
           count_obs_in = count_obs_in+1
           call obs_headSet_i(lobsSpaceData,OBS_ST1,headerIndex,  &
             ibclr( obs_headElem_i(lobsSpaceData,OBS_ST1,headerIndex),05))
        endif
     enddo ! headerIndex
     write(*,*) 'routine checkObsMpiIP: number of observation headers in this lat-lon tile: ', count_obs_in
  else
     do headerIndex = 1, obs_numheader(lobsSpaceData)
        call obs_headSet_i(lobsSpaceData,OBS_ST1,headerIndex,  &
             ibclr( obs_headElem_i(lobsSpaceData,OBS_ST1,headerIndex),05))
     enddo
  endif
end subroutine checkObsMpiIP