module mysubs

contains

  subroutine init(a)
    ! initial values for a: a(i,j, k) = i+j+k

    use kinds
    implicit none
    
    real(kind=REAL8), dimension(:,:,:)  :: a
    integer                             :: n, i, j, k
 
    n = size(a, 1)
    
    do i=1,n
       do j=1,n
          do k=1,3
             a(i,j,k) = i + j + k
          enddo
       enddo
    enddo
    return
  end subroutine init

  subroutine check(a)
    ! check results
    ! here: print total sum
    
    use kinds
    implicit none
    
    real(kind=REAL8), dimension(:,:,:)  :: a
    real(kind=REAL8)                    :: sum1, sum2
    integer                             :: n
    
    n = size(a, 1)

    sum1 = sum(a)
    sum2 = 3*n**3 + 9*n**2
    
    print *, 'sum is       : ', sum1
    print *, 'and should be: ', sum2
    
    return
  end subroutine check

  function f(x, work)
    ! time consuming way of setting f = x + eps
    use kinds
    implicit none

    real(kind=REAL8) :: f, x
    integer          :: work
    integer          :: i
    real(kind=REAL8) :: t1, t2
    
    t1 = x
    do i= 1, work
       t1 = cos(t1)
    end do
    
    t2 = x
    do i= 1, work
       t2 = sin(t2)
    end do
  
    f = x + t1 + t2 - 0.7390851332151607 
  end function f


  subroutine smooth(a, direction, work)
    ! smoothes part of a
    use kinds
    implicit none

    real(kind=REAL8), dimension(:,:,:) :: a
    integer          :: direction, work
    
    integer          :: i, j, k, n
    
    n = size(a, 1)
    k = direction

    do i=2, n-1
       do j=2, n-1
          a(i,j,k) = (a(i-1,j,k) + f(a(i,j,k),work) + a(i+1,j,k) + &
                      a(i,j-1,k) + a(i,j+1,k))/5.0
       end do
    end do

    return
  end subroutine smooth


end module mysubs


program section1

  use kinds
  use mysubs
  implicit none

  integer, parameter                 :: n = 20
  integer, parameter                 :: work = 100000

  real(kind=REAL8), dimension(n,n,3) :: a
      
  call init(a)   ! initial values for a

  !$OMP PARALLEL SECTIONS
  !$OMP SECTION
  call smooth(a, 1, work)
  !$OMP SECTION
  call smooth(a, 2, work)
  !$OMP SECTION
  call smooth(a, 3, work)
  !$OMP END PARALLEL SECTIONS

  call check(a)  ! check result

end program section1