-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathrelax-omp.f90
321 lines (213 loc) · 6.9 KB
/
relax-omp.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
! Do brute force relaxation on a 2-d Poisson equation. Here we
! experiment with OpenMP
!
! We solve
! u'' = g(x),
! u(x=0,: ) = 0, u(x=1,: ) = 1
! u(: ,y=0) = 0, u(: ,y=1) = 1
!
!with
! g(x) = cos(x)*sin(y)
!
!
! compile with:
!
! gfortran -fopenmp -O -o relax relax.f90
!
! run with:
!
! export OMP_NUM_THREADS=2; time ./relax
!
! M. Zingale (2010-03-07)
program relax
USE omp_lib
implicit none
integer, parameter :: nx = 1024 ! number of interior zones in x
integer, parameter :: ny = nx ! number of interior zones in y
integer, parameter :: ng = 1 ! number of guardcells
integer, parameter :: nsmooth = 2500 ! number of smoothing blocks
! set the lo/hi boundary conditions in each coordinate direction
double precision, parameter :: bc_lo_x = 0.d0
double precision, parameter :: bc_hi_x = 0.d0
double precision, parameter :: bc_lo_y = 0.d0
double precision, parameter :: bc_hi_y = 0.d0
! imin/imax and jmin/jmax will always point to the starting and
! ending index of the interior zones
integer :: imin, imax, jmin, jmax
double precision :: xmin, xmax, ymin, ymax, dx, dy
double precision :: source_norm
double precision :: xx, yy
integer :: i, j, n
double precision, dimension(:,:), allocatable :: v, w, f
double precision :: temp
!real :: start, finish
double precision :: startOMP, finishOMP
! measure time to run
! cpu_time() is a F95 intrinsic, but note that it adds up the time
! for all threads -- it is not wallclock time
!call cpu_time(start)
startOMP = omp_get_wtime()
! initialize the solution and rhs arrays
allocate(f(-ng:nx+ng-1,-ng:ny+ng-1))
allocate(v(-ng:nx+ng-1,-ng:ny+ng-1))
allocate(w(-ng:nx+ng-1,-ng:ny+ng-1))
! integers indicating the range of valid data
imin = 0 ! index 0 is the first valid cell
imax = nx-1
jmin = 0 ! index 0 is the first valid cell
jmax = ny-1
!$OMP PARALLEL DO PRIVATE (i,j)
do j =jmin-ng, jmax+ng
do i = imin-ng, imax+ng
f(i,j) = 0.d0
v(i,j) = 0.d0
enddo
enddo
!$OMP END PARALLEL DO
! set the boundary conditions
v(-ng:-1 ,:) = bc_lo_x
v(nx:nx+ng-1,:) = bc_hi_x
v(:,-ng:-1) = bc_lo_y
v(:,ny:ny+ng-1) = bc_hi_y
! setup the grid
xmin = 0.d0
xmax = 1.d0
dx = (xmax - xmin)/dble(nx)
ymin = 0.d0
ymax = 1.0d0
dy = (ymax - ymin)/dble(ny)
if (dx /= dy) stop "ERROR: dx /= dy"
! fill the RHS of with the true RHS
!$OMP PARALLEL DO PRIVATE (i,j,xx,yy)
do j = jmin, jmax
yy = (dble(j) + 0.5d0)*dy + ymin
do i = imin, imax
xx = (dble(i) + 0.5d0)*dx + xmin
f(i,j) = g(xx,yy)
enddo
enddo
!$OMP END PARALLEL DO
! compute the source norm -- we will use this for error estimating
source_norm = error(nx, ny, ng, dx, dy, f)
! relax
call smooth(nx, ny, ng, dx, dy, &
bc_lo_x, bc_hi_x, bc_lo_y, bc_hi_y, &
v, f, nsmooth)
! compare to the true solution
!$OMP PARALLEL DO PRIVATE (i,j,xx,yy)
do j = jmin, jmax
yy = (dble(j) + 0.5d0)*dy + ymin
do i = imin, imax
xx = (dble(i) + 0.5d0)*dx + xmin
w(i,j) = true(xx,yy) - v(i,j)
enddo
enddo
!$OMP END PARALLEL DO
close (unit=10)
100 format(1x, 1g13.6, 1x, 1g13.6, 1x, 1g13.6, 1x, 1g13.6)
temp = error(nx, ny, ng, dx, dy, w)
finishOMP = omp_get_wtime()
!call cpu_time(finish)
99 format(1x, "nx: ", i4, 3x, "threads: ", i3, 3x, "wallclock: ", g9.4, 3x, &
"error: ", g10.5)
write(*,99) nx, omp_get_max_threads(), finishOMP-startOMP, temp
contains
!=============================================================================
! g
!=============================================================================
function g(x,y)
! the RHS of the Poisson equation we are solving
implicit none
double precision :: g, x, y
double precision, parameter :: pi = 3.14159265358979323846d0
g = -2.d0*(2.0*pi)**2 * sin(2.0*pi*x) * sin(2.0*pi*y)
return
end function g
!=============================================================================
! true
!=============================================================================
function true(x,y)
! the analytic solution to our equation
implicit none
double precision true, x, y
double precision, parameter :: pi = 3.14159265358979323846d0
true = sin(2.0*pi*x) * sin(2.0*pi*y)
return
end function true
!=============================================================================
! error
!=============================================================================
function error(nx, ny, ng, dx, dy, v)
! compute the L2 norm
implicit none
integer :: nx, ny, ng
double precision :: dx, dy
double precision :: v(-ng:,-ng:)
integer :: i, j, imin, imax, jmin, jmax
double precision :: error
imin = 0
imax = nx-1
jmin = 0
jmax = ny-1
error = 0.d0
!$OMP PARALLEL DO REDUCTION(+:error) PRIVATE (i,j)
do j = jmin, jmax
do i = imin, imax
error = error + v(i,j)**2
enddo
enddo
!$OMP END PARALLEL DO
error = dx*dy*error ! make it grid invariant
error = sqrt(error)
return
end function error
!=============================================================================
! smooth
!=============================================================================
subroutine smooth(nx, ny, ng, dx, dy, &
bc_lo_x, bc_hi_x, bc_lo_y, bc_hi_y, &
v, f, nsmooth)
! given a solution vector, v, and a RHS vector, f,
! smooth v to better satisfy the equation. This is
! done in place, using Red-Black Gauss-Seidel
! hi and lo Dirichlet boundary conditions are also passed.
! Because we are finite-volume, and therefore, cell-centered, we
! need to extrapolate to match the desired Dirichlet BC.
implicit none
integer :: nx, ny, ng, nsmooth
double precision :: dx, dy
double precision :: bc_lo_x, bc_hi_x, bc_lo_y, bc_hi_y
double precision, dimension(-ng:,-ng:) :: v, f
integer :: i, j, m, ioff, color
integer :: imin, imax, jmin, jmax
imin = 0
imax = nx -1
jmin = 0
jmax = ny -1
! do some smoothing -- Red-Black Gauss-Seidel
do m = 1, nsmooth
do color = 0, 1
! set the guardcells to give the proper boundary condition, using
! extrapolation
v(imin-1,:) = 2*bc_lo_x - v(imin,:)
v(imax+1,:) = 2*bc_hi_x - v(imax,:)
v(:,jmin-1) = 2*bc_lo_y - v(:,jmin)
v(:,jmax+1) = 2*bc_hi_y - v(:,jmax)
!$OMP PARALLEL DO PRIVATE (i,j,ioff)
do j = jmin, jmax
if (color == 0) then
ioff = mod(j,2)
else
ioff = 1 - mod(j,2)
endif
do i = imin+ioff, imax, 2
v(i,j) = 0.25d0*(v(i-1,j) + v(i+1,j) + &
v(i,j-1) + v(i,j+1) - dx*dx*f(i,j))
enddo
enddo
!$OMP END PARALLEL DO
enddo
enddo
return
end subroutine smooth
end program relax