Suppose I would like to integrate a function that depends on two parameters, alpha and beta. The function inputs should be x,alpha,beta, but the integrator (a numerical procedure that computes the integral) wants the function with one input only, x, as in here:
module integrals
implicit none
contains
function simpson(f, a, b) result(s)
! Taken from https://fortran-lang.org/en/learn/best_practices/callbacks/
implicit none
real(8), intent(in) :: a, b
interface
function f(x) result(func)
real(8), intent(in) :: x
real(8) :: func
end function
end interface
real(8) :: s
s = (b-a) / 6 * (f(a) + 4*f((a+b)/2) + f(b))
end function simpson
end module integrals
One way of doing this is the following:
program main
use integrals, only: simpson
implicit none
real(8) :: alpha, beta
real(8) :: myint
alpha = 1d0
beta = 2d0
myint = simpson(myfunc, 0.0d0, 1.0d0)
contains
function myfunc(x) result(res)
real(8), intent(in) :: x
real(8) :: res
res = alpha*x**2+beta
end function myfunc
end program main
So far so good, but the problem is that I would like to vary alpha and beta among several possible combinations, and to compute the integral of my function for each combo (alpha,beta). Something like this:
program main
use integrals, only: simpson
implicit none
integer, parameter :: n = 3
integer :: i1, i2
real(8) :: alpha, beta, alpha_vec(n), beta_vec(n), store(n, n)
real(8) :: myint
alpha_vec = [0.01d0, 2.0d0, 3.0d0]
beta_vec = [1.0d0, 0.0d0, 3.0d0]
!$omp parallel default(shared) private(i1,i2,myint,alpha,beta)
!$omp do collapse(2)
do i2=1, n
do i1=1, n
alpha = alpha_vec(i1)
beta = beta_vec(i2)
myint = simpson(myfunc, 0.0d0, 1.0d0)
write(*,*) 'Integral = ', myint
store(i1, i2) = myint
enddo
enddo
!$omp enddo
!$omp end parallel
write(*,*) 'Results:'
do i1=1, n
write(*,*) store(i1, :)
enddo
contains
function myfunc(x) result(res)
real(8), intent(in) :: x
real(8) :: res
res = alpha*x**2+beta
end function myfunc
end program main
Now, the code above works OK in serial, but as soon as I use openMP it gives garbage results. Reading online I found out that I should define alpha and beta as module variables, and declare them as threadprivate
. Unfortunately I’m a bit lost, so I’d be very grateful if anyone has suggestions
Btw, I found very useful the “best practice” example on Callbacks — Fortran Programming Language but it does not talk about parallelization.