-
Notifications
You must be signed in to change notification settings - Fork 2
/
pi_monte_carlo_co_sum_openmp.f90
79 lines (67 loc) · 2.87 KB
/
pi_monte_carlo_co_sum_openmp.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
! Computes an approximation of Pi with a Monte Carlo algorithm
! Co_sum with final results
! Vincent Magnin, 2021-04-22
! and Brad Richardson
! and Ryan Bignell
! Last modification: 2024-09-04
! MIT license
! $ caf -Wall -Wextra -std=f2018 -pedantic -O3 -fopenmp m_xoroshiro128plus.f90 pi_monte_carlo_co_sum_openmp.f90
! $ cafrun -n 4 ./a.out
! or with ifx :
! $ ifx -O3 -qopenmp -coarray m_xoroshiro128plus.f90 pi_monte_carlo_co_sum_openmp.f90
program pi_monte_carlo_co_sum_openmp
use, intrinsic :: iso_fortran_env, only: wp=>real64, int64
use m_xoroshiro128plus
use omp_lib, only: omp_get_thread_num, omp_get_num_threads
implicit none
type(rng_t) :: rng ! xoroshiro128+ pseudo-random number generator
real(wp) :: x, y ! Coordinates of a point
integer(int64) :: n ! Total number of points
integer(int64) :: k ! Points into the quarter disk
integer(int64) :: i ! Loop counter
integer(int64) :: n_per_image ! Number of parallel images
integer :: t1, t2 ! Clock ticks
real :: count_rate ! Clock ticks per second
integer :: thread ! OpenMP thread number
integer :: nth
n = 1000000000
k = 0
call system_clock(t1, count_rate)
!$OMP PARALLEL DEFAULT(NONE) SHARED(n_per_image,n) PRIVATE(thread, nth, i, x, y, rng) REDUCTION(+: k)
thread = omp_get_thread_num()
! Each image have its own RNG seed, thanks to rng%jump() which
! generates non-overlapping subsequences for parallel computations:
call rng%seed([ -1337_i8, 9812374_i8 ])
! Threads are numbered from 0, images from 1.
! We compute a unique number for each task, starting from 1:
nth = (this_image() - 1) * omp_get_num_threads() + (thread + 1)
if (nth /= 1) then
do i = 2, nth
call rng%jump()
end do
end if
x = rng%U01()
n_per_image = n / num_images()
write(*, '(a, i3, a, i3)', advance='no') "Image ", this_image(), "/", num_images()
write(*, '(a, i11, a)') " will compute", n_per_image, " points"
!$OMP DO SCHEDULE(STATIC)
do i = 1, n_per_image
! Computing a random point (x,y) into the square 0<=x<1, 0<=y<1:
x = rng%U01()
y = rng%U01()
! Is it in the quarter disk (R=1, center=origin) ?
if ((x**2 + y**2) < 1.0_wp) k = k + 1
end do
!$OMP END DO
!$OMP END PARALLEL
! At the end:
call co_sum(k, result_image = 1)
if (this_image() == 1) then
write(*,*)
write(*, '(a, i0, a, i0)', advance='no') "4 * ", k, " / ", n
write(*, '(a, f17.15)') " = ", (4.0_wp * k) / n
call system_clock(t2)
write(*,'(a, f6.3, a)') "Execution time: ", (t2 - t1) / count_rate, " s"
write(*,'(a)') "---------------------------------------------------"
end if
end program pi_monte_carlo_co_sum_openmp