C ******************************************************************************
C                Example 14 : Omp_MatrixTranspose.f
C
C   Objective    : Write an OpenMP Program for Transpose of a Matrix
C                  and measure the performance
C                  This example demonstrates the use of
C                  PARALLEL DO directive and Private clause
C
C   Input        : Size of Matrix 
C
C   Output       : Each thread transposes assaigned Row of Matrix, 
C                  time taken for this computation and Mflop/s
C
C   Necessary Condition : Number of threads should be less than or
C                         equal to number of processors of a SMP node.
C
C ******************************************************************************

      program MatTranspose

      integer DATA_SIZE
      parameter (DATA_SIZE = 101)

 	   integer  Matrix_size, NoofRows, NoofCols, i, j
 	   real     Matrix_A(DATA_SIZE, DATA_SIZE)
      real     Trans(DATA_SIZE, DATA_SIZE)
      real     Checkoutput(DATA_SIZE, DATA_SIZE), flops
      real     Mflops
      integer  NoofOperations, ValidOutput
      real     tt1(2), tt2(2)
      real     toh1, toh2, toh

      toh1 = etime(tt1)
      toh2 = etime(tt2)
      toh  = toh2 - toh1

      print *,'Input Size of Matrix'
      read(*,*) MatrixSize
      Iterations = 100

      if((MatrixSize .le. 0) .or. (MatrixSize .gt. DATA_SIZE)) then
        print *,'Invalid MatrixSize.'
        print *,'Please try with another number less than', DATA_SIZE+1
        goto 100
      endif


C 	 Matrix Elements 

      do i = 1, MatrixSize
         do j = 1, MatrixSize
            Matrix_A(i, j) = 1.0 * i
 			   Checkoutput(i,j) = 0.0
 			   Trans(i,j) = 0.0
         enddo
      enddo

      t1 = etime(tt1)
 
C 	OpenMP Parallel For Directive 
 
C$OMP PARALLEL DO PRIVATE(j)
      do i = 1, MatrixSize
 	      do j = 1, MatrixSize
 			   Trans(j,i) = Matrix_A(i,j)
         enddo
      enddo

      t2 = etime(tt2)

C 	Serial Computation 
 
      do i = 1, MatrixSize
 	      do j = 1, MatrixSize
 			   CheckOutput(j,i) = Matrix_A(i,j)
         enddo
      enddo

      do j = 1, MatrixSize
         do i = 1, MatrixSize
            if(Trans(i,j) .ne. CheckOutput(i,j)) then
               ValidOutput = 0
            else
               ValidOutput = 1
            endif
         enddo
      enddo

      if(ValidOutput .eq. 1) then
        print*,"------ Correct Result -----"
      else
        print*,"------ Wrong Result -----"
      endif

      print*,"Input Matrix"
      do i = 1, MatrixSize
         write (6,10)(Matrix_A(i,j),j=1,MatrixSize)
      enddo

      print*,"Traspose of Matrix"
      do i = 1, MatrixSize
         write (6,10)(Trans(i,j),j=1,MatrixSize)
      enddo
 10   format(8(2x,f8.2))

      NoofOperations = 2*MatrixSize
      TimeOverhead = (t2-t1-toh) / Iterations
      Mflops = NoofOperations / (TimeOverhead * 1000000)

      print *,'******************************'
      print *,'Size of Matrix=',MatrixSize
      print *,'Time Taken (seconds) =',(t2-t1-toh)
      print *,'Mflop/s =',Mflops
      print *,'******************************'

 100  stop
      end
