module testCasesMpi
  use testHelperMpi
  use gamapp_mpi
  use usergamic

  implicit none


contains

  @before
  subroutine firstSerial(this)
      class (MpiTestMethod), intent(inout) :: this

  end subroutine firstSerial

  @after
  subroutine lastSerial(this)
      class (MpiTestMethod), intent(inout) :: this

  end subroutine lastSerial

  @test(npes=[8])
  subroutine testBlast3D_8(this)
      class (MpiTestMethod), intent(inout) :: this

      type(gamAppMpi_T) :: gameraAppMpi
      type(XML_Input_T) :: xmlInp

      call setMpiReal()

      gameraAppMpi%gOptions%userInitFunc => initUser
      gameraAppMpi%gOptionsMpi%gamComm = getMpiF08Communicator(this)
      xmlInp = New_XML_Input('blast3d_large8.xml','Kaiju',.true.)
      call gameraAppMpi%InitModel(xmlInp)

      do while ((gameraAppMpi%Model%tFin - gameraAppMpi%Model%t) > 1e-15)
        call stepGamera_mpi(gameraAppMpi)

        if (gameraAppMpi%Model%IO%doConsole(gameraAppMpi%Model%t)) then
            call consoleOutput(gameraAppMpi%Model,gameraAppMpi%Grid,gameraAppMpi%State)
        endif

        if (gameraAppMpi%Model%IO%doOutput(gameraAppMpi%Model%t)) then
            call fOutput(gameraAppMpi%Model,gameraAppMpi%Grid,gameraAppMpi%State)
        endif

      end do
      write(*,*) 'End time = ', gameraAppMpi%Model%t

  end subroutine testBlast3D_8

  @test(npes=[2])
  subroutine testBlast3D_2(this)
      class (MpiTestMethod), intent(inout) :: this

      type(gamAppMpi_T) :: gameraAppMpi
      type(XML_Input_T) :: xmlInp

      call setMpiReal()

      gameraAppMpi%gOptions%userInitFunc => initUser
      gameraAppMpi%gOptionsMpi%gamComm = getMpiF08Communicator(this)
      xmlInp = New_XML_Input('blast3d_large2.xml','Kaiju',.true.)
      call gameraAppMpi%InitModel(xmlInp)

      do while ((gameraAppMpi%Model%tFin - gameraAppMpi%Model%t) > 1e-15)
        call stepGamera_mpi(gameraAppMpi)

        if (gameraAppMpi%Model%IO%doConsole(gameraAppMpi%Model%t)) then
            call consoleOutput(gameraAppMpi%Model,gameraAppMpi%Grid,gameraAppMpi%State)
        endif

        if (gameraAppMpi%Model%IO%doOutput(gameraAppMpi%Model%t)) then
            call fOutput(gameraAppMpi%Model,gameraAppMpi%Grid,gameraAppMpi%State)
        endif

      end do
      write(*,*) 'End time = ', gameraAppMpi%Model%t

  end subroutine testBlast3D_2

  !this test must be at the bottom so that the data is generated by the two tests above
  @test(npes=[1])
  subroutine compareBlastWaves(this)
      class (MpiTestMethod), intent(inout) :: this

      type(IOVAR_T), dimension(25) :: IOVars
      real(rp), allocatable :: p8(:,:,:), p2(:,:,:)
      integer :: i,j,k,ni,nj,nk,ni2,nj2,nk2
      character(len=strLen) :: h5Str, gStr, errMsg

      call setMpiReal()

      h5Str = trim('blast')
      gStr = '/Step#99'
      call ClearIO(IOVars)
      call AddInVar(IOVars,"P")

      ! manually read in the 2 parts of blast3d_large2 and also determine the size of the data
      h5Str = 'blast3d_large2_0002_0001_0001_0000_0000_0000.gam.h5'
      call ReadVars(IOVars,.false.,h5Str,gStr)
      ni = 2*IOVars(1)%dims(1)
      nj = IOVars(1)%dims(2)
      nk = IOVars(1)%dims(3)
      ni2 = ni/2
      nj2 = nj/2
      nk2 = nk/2
      allocate(p2(ni,nj,nk))
      allocate(p8(ni,nj,nk))
      call IOArray3DFill(IOVars,"P",p2(1:ni2,:,:))
      call ClearIO(IOVars)
      call AddInVar(IOVars,"P")
      h5Str = 'blast3d_large2_0002_0001_0001_0001_0000_0000.gam.h5'
      call ReadVars(IOVars,.false.,h5Str,gStr)
      call IOArray3DFill(IOVars,"P",p2(ni2+1:ni,:,:))
      call ClearIO(IOVars)

      ! loop to read in the parts blast3d_large8
      do i=1,2
          do j=1,2
               do k=1,2
                   call AddInVar(IOVars,"P")
                   write(h5Str,'(A,I0,A,I0,A,I0,A)') 'blast3d_large8_0002_0002_0002_000',i-1,'_000',j-1,'_000',k-1,'.gam.h5'
                   call ReadVars(IOVars,.false.,h5Str,gStr)
                   call IOArray3DFill(IOVars,"P",p8(1+(i-1)*ni2:i*ni2,1+(j-1)*nj2:j*nj2,1+(k-1)*nk2:k*nk2))
                   call ClearIO(IOVars)
               enddo
          enddo
      enddo

      ! check values
      do i=1,ni
          do j=1,nj
               do k=1,nk
                   write(errMsg,'(A,I0,A,I0,A,I0,A)') 'Blast wave values not equal at (',i,',',j,',',k,')'
                   @assertEqual(p2(i,j,k),p8(i,j,k),1e-12,trim(errMsg))
               enddo
          enddo
      enddo

  end subroutine compareBlastWaves

end module testCasesMpi

