forked from csc-training/summerschool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mandelbrot.F90
129 lines (94 loc) · 3.31 KB
/
mandelbrot.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
program mandelbrot
use iso_fortran_env, only : REAL64
use pngwriter
use omp_lib
implicit none
integer, parameter :: dp = REAL64
integer, parameter :: max_iter_count = 512
integer, parameter :: max_depth = 6
integer, parameter :: min_size = 32
integer, parameter :: subdiv = 4
integer, parameter :: w = 2048
integer, parameter :: h = w
integer, pointer, dimension(:,:) :: iter_counts
integer :: stat
complex(dp) :: cmin, cmax
real(dp) :: t0, t1
allocate(iter_counts(w, h))
t0 = omp_get_wtime()
cmin = (-1.5, -1.0)
cmax = (0.5, 1.0)
! TODO create parallel region. How many threads should be calling
! mandelbrot_block in this uppermost level?
call mandelbrot_block(iter_counts, w, h, cmin, cmax, 0, 0, w, 1)
t1 = omp_get_wtime()
stat = save_png(iter_counts, h, w, 'mandelbrot.png')
deallocate(iter_counts)
write(*,*) 'Mandelbrot set computed in', t1 - t0, 's'
contains
! Computes the Mandelbrot image recursively
! At each call, the image is divided into smaller blocks (by a factor of
! subdiv), and the function is called recursively with arguments corresponding
! to subblock. When maximum recursion depth is reached or size of block
! is smaller than predefined minimum, one starts to calculate actual pixel
! values
!
! - - - - - - - - ----- -----
! | | | | | |
! | | ----- -----
! | | --> --> ...
! | | ----- -----
! | | | | | |
! | | ----- -----
! ---------------
!
recursive subroutine mandelbrot_block(iter_counts, w, h, cmin, cmax, &
x0, y0, d, depth)
implicit none
integer, pointer, dimension(:,:), intent(inout) :: iter_counts
integer, intent(in) :: w, h, x0, y0, d, depth
complex(dp), intent(in) :: cmin, cmax
integer :: block_size, i, j
! TODO Parallelize the recursive function call
! with OpenMP tasks
block_size = d / subdiv
if ((depth + 1 < max_depth) .and. (block_size > min_size)) then
! Subdivide recursively
do i=0, subdiv - 1
do j=0, subdiv - 1
call mandelbrot_block(iter_counts, w, h, cmin, cmax, &
x0 + i*block_size, y0 + j*block_size, &
block_size, depth + 1)
end do
end do
else
! Last recursion level reached, calculate the values
do j = y0 + 1, y0 + d
do i = x0 + 1, x0 + d
iter_counts(i, j) = kernel(h, w, cmin, cmax, i-1, j-1)
end do
end do
end if
end subroutine mandelbrot_block
! Calculate iteration count for a pixel.
! This function does not need to be edited
integer function kernel(h, w, cmin, cmax, x, y)
implicit none
integer, intent(in) :: h, w, x, y
complex(dp), intent(in) :: cmin, cmax
integer :: iteration
complex(dp) :: z, dc, c
real(dp) :: fx, fy
dc = cmax - cmin
fx = real(x, dp) / w
fy = real(y, dp) / h
c = cmin + fx * real(dc) + fy * imag(dc) * (0.0, 1.0)
z = c
iteration = 0
do while (iteration < max_iter_count .and. abs(z)**2 < 4)
z = z**2 + c
iteration = iteration + 1
end do
kernel = iteration
end function kernel
end program mandelbrot