program array_update

!          Variables
!

      include "f_hpm.h"

!  These variables size the arrays and specify the number and identity of threads.
       integer :: arraysize, nthreads,  np, iam

!  These variables allow evaluating the FORTRAN, DATE_AND_TIME intrinsic call.
       integer :: start, stop, lilstart, lilstop, bigstop, bigstart, total, liltotal
       integer, dimension(8) :: date_time
       character (len=10), dimension (3) ::  big_ben

!  These variables create and index the arrays.
       real*8  :: privDbl
       integer :: privIndx, i

!      Thread variables.
       integer ::  omp_get_num_threads, omp_get_thread_num, omp_set_num_threads

       real*8, dimension(:), allocatable :: x, y

       integer :: taskID, instID
       character (len=15)  :: progName, label

! HPM Area

       label = "Initialize"
       progName = "libhpm_test"
       instID = 1

       call f_hpminit( taskID, progName )
       call f_hpmstart( instID, label )
 
 

!  Execution area

!  Ask for the sizes of the arrays.
       write(*,*) "Please enter the integer size of the arrays."
       read(*,*)  arraysize
 
 

!  Do set-ups.
       nthreads = 4
       allocate(x(0:arraysize))
       allocate(y(0:arraysize))

       call f_hpmstop( instID )

       label = "load_arrays"
       instID = 1 +  instID

       call f_hpmstart( instID, label )
 

! Pre-load x array
!$omp parallel do private(i)
       do i = 0, arraysize
          x(i) = (real(i)) / (i + 1000)
       end do
!$omp end parallel do

!  Initialize the clock
       call DATE_AND_TIME(big_ben(1), big_ben(2), big_ben(3),  date_time)
       bigstart = date_time(6)
       start = date_time(7)
       lilstart = date_time(8)

!   Initialize the threads
     omp_set_num_threads =  nthreads
!$omp parallel private(np,iam)
        np  = omp_get_num_threads()
        iam = omp_get_thread_num()
        write(*,*) 'My thread number is ', iam, '/', np-1
!$omp end parallel

       call f_hpmstop( instID )

       label = "Do_work"
       instID = 1 +  instID

       call f_hpmstart( instID, label )
 
 

!Do the work.
!$omp parallel do private(privIndx, privDbl)
      do 300 i=0, arraysize
          do privIndx = 1, 16
             privDbl = real(privIndx) / 16.
             y(i) = (sin( exp( cos( -exp( sin( x(i))))))) + cos(privDbl)
          end do
  300 continue
!$omp end parallel do
 

!  Stop the clock
       call DATE_AND_TIME(big_ben(1), big_ben(2), big_ben(3),  date_time)
       bigstop = date_time(6)
       stop = date_time(7)
       lilstop = date_time(8)

       call f_hpmstop( instID )

       call f_hpmterminate( taskID )

!  Ccompute the run time and write the result.
       if (lilstop - lilstart < 0) then
          stop  = stop  + 1
          liltotal = 1000 -  abs(lilstop - lilstart)
       else
          liltotal = lilstop - lilstart
       endif
       if (stop - start < 0) then
          bigstop = bigstop + 1
          total = 60 - abs(stop - start)
       else
          total = stop - start
       endif
       if ((bigstop - bigstart) < 0) then
          write (*,*) "Timing error"
       else
          write(*,*) "Wall time = ", total,".", liltotal, " Seconds", &
          & " for arraysize = ", arraysize
       endif

      write(*,*) "Program successfully terminated."

       end program