-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathexchangeable_implementation.f90
248 lines (198 loc) · 8.92 KB
/
exchangeable_implementation.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
submodule(exchangeable_interface) exchangeable_implementation
use assertions_interface, only : assert, assertions
use grid_interface, only : grid_t
implicit none
integer, parameter :: default_halo_size=1
integer, save, allocatable :: neighbors(:)
integer, save :: north_neighbor, south_neighbor, halo_size
integer, save :: east_neighbor, west_neighbor
contains
module subroutine const(this,grid,initial_value,halo_width)
class(exchangeable_t), intent(inout) :: this
type(grid_t), intent(in) :: grid
real, intent(in) :: initial_value
integer, intent(in), optional :: halo_width
integer :: n_neighbors, current
integer :: ims,ime,kms,kme,jms,jme
if (present(halo_width)) then
halo_size = halo_width
else
halo_size = default_halo_size
end if
if (allocated(this%local)) deallocate(this%local)
this%north_boundary = (grid%yimg == grid%yimages)
this%south_boundary = (grid%yimg == 1)
this%east_boundary = (grid%ximg == grid%ximages)
this%west_boundary = (grid%ximg == 1)
associate( halo_south => merge(0,halo_size,this%south_boundary), &
halo_north => merge(0,halo_size,this%north_boundary), &
halo_east => merge(0,halo_size,this%east_boundary), &
halo_west => merge(0,halo_size,this%west_boundary))
ims = grid%ims - halo_east
ime = grid%ime + halo_west
jms = grid%jms - halo_south
jme = grid%jme + halo_north
kms = grid%kms
kme = grid%kme
allocate(this%local(ims:ime,kms:kme,jms:jme), source=initial_value)
end associate
allocate( this%halo_south_in( grid%ns_halo_nx+halo_size*2, grid%halo_nz, halo_size )[*], source=initial_value)
allocate( this%halo_north_in( grid%ns_halo_nx+halo_size*2, grid%halo_nz, halo_size )[*], source=initial_value)
allocate( this%halo_east_in( halo_size, grid%halo_nz, grid%ew_halo_ny+halo_size*2)[*], source=initial_value)
allocate( this%halo_west_in( halo_size, grid%halo_nz, grid%ew_halo_ny+halo_size*2)[*], source=initial_value)
! set up the neighbors array so we can sync with our neighbors when needed
if (.not.allocated(neighbors)) then
associate(me=>this_image())
south_neighbor = me - grid%ximages
north_neighbor = me + grid%ximages
east_neighbor = me + 1
west_neighbor = me - 1
n_neighbors = merge(0,1,this%south_boundary) &
+merge(0,1,this%north_boundary) &
+merge(0,1,this%east_boundary) &
+merge(0,1,this%west_boundary)
n_neighbors = max(1, n_neighbors)
allocate(neighbors(n_neighbors))
current = 1
if (.not. this%south_boundary) then
neighbors(current) = south_neighbor
current = current+1
endif
if (.not. this%north_boundary) then
neighbors(current) = north_neighbor
current = current+1
endif
if (.not. this%east_boundary) then
neighbors(current) = east_neighbor
current = current+1
endif
if (.not. this%west_boundary) then
neighbors(current) = west_neighbor
current = current+1
endif
! if current = 1 then all of the boundaries were set, just store ourself as our "neighbor"
if (current == 1) then
neighbors(current) = me
endif
end associate
endif
end subroutine
module subroutine send(this)
class(exchangeable_t), intent(inout) :: this
if (.not. this%north_boundary) call this%put_north
if (.not. this%south_boundary) call this%put_south
if (.not. this%east_boundary) call this%put_east
if (.not. this%west_boundary) call this%put_west
end subroutine
module subroutine retrieve(this, no_sync)
class(exchangeable_t), intent(inout) :: this
logical, intent(in), optional :: no_sync
if (.not. present(no_sync)) then
sync images( neighbors )
else
if (.not. no_sync) then
sync images( neighbors )
endif
endif
if (.not. this%north_boundary) call this%retrieve_north_halo
if (.not. this%south_boundary) call this%retrieve_south_halo
if (.not. this%east_boundary) call this%retrieve_east_halo
if (.not. this%west_boundary) call this%retrieve_west_halo
end subroutine
module subroutine exchange(this)
class(exchangeable_t), intent(inout) :: this
if (.not. this%north_boundary) call this%put_north
if (.not. this%south_boundary) call this%put_south
if (.not. this%east_boundary) call this%put_east
if (.not. this%west_boundary) call this%put_west
sync images( neighbors )
if (.not. this%north_boundary) call this%retrieve_north_halo
if (.not. this%south_boundary) call this%retrieve_south_halo
if (.not. this%east_boundary) call this%retrieve_east_halo
if (.not. this%west_boundary) call this%retrieve_west_halo
end subroutine
module subroutine put_north(this)
class(exchangeable_t), intent(inout) :: this
integer :: n, nx
n = ubound(this%local,3)
nx = size(this%local,1)
if (assertions) then
!! gfortran 6.3.0 doesn't check coarray shape conformity with -fcheck=all so we verify with an assertion
call assert( shape(this%halo_south_in(:nx,:,1:halo_size)[north_neighbor]) &
== shape(this%local(:,:,n-halo_size+1:n)), &
"put_north: conformable halo_south_in and local " )
end if
!dir$ pgas defer_sync
this%halo_south_in(1:nx,:,1:halo_size)[north_neighbor] = this%local(:,:,n-halo_size*2+1:n-halo_size)
end subroutine
module subroutine put_south(this)
class(exchangeable_t), intent(inout) :: this
integer :: start, nx
start = lbound(this%local,3)
nx = size(this%local,1)
if (assertions) then
!! gfortran 6.3.0 doesn't check coarray shape conformity with -fcheck=all so we verify with an assertion
call assert( shape(this%halo_north_in(:nx,:,1:halo_size)[south_neighbor]) &
== shape(this%local(:,:,start:start+halo_size-1)), &
"put_south: conformable halo_north_in and local " )
end if
!dir$ pgas defer_sync
this%halo_north_in(1:nx,:,1:halo_size)[south_neighbor] = this%local(:,:,start+halo_size:start+halo_size*2-1)
end subroutine
module subroutine retrieve_north_halo(this)
class(exchangeable_t), intent(inout) :: this
integer :: n, nx
n = ubound(this%local,3)
nx = size(this%local,1)
this%local(:,:,n-halo_size+1:n) = this%halo_north_in(:nx,:,1:halo_size)
end subroutine
module subroutine retrieve_south_halo(this)
class(exchangeable_t), intent(inout) :: this
integer :: start, nx
start = lbound(this%local,3)
nx = size(this%local,1)
this%local(:,:,start:start+halo_size-1) = this%halo_south_in(:nx,:,1:halo_size)
end subroutine
module subroutine put_east(this)
class(exchangeable_t), intent(inout) :: this
integer :: n, ny
n = ubound(this%local,1)
ny = size(this%local,3)
if (assertions) then
!! gfortran 6.3.0 doesn't check coarray shape conformity with -fcheck=all so we verify with an assertion
call assert( shape(this%halo_west_in(1:halo_size,:,:ny)[east_neighbor]) &
== shape(this%local(n-halo_size*2+1:n-halo_size,:,:)), &
"put_east: conformable halo_west_in and local " )
end if
!dir$ pgas defer_sync
this%halo_west_in(1:halo_size,:,1:ny)[east_neighbor] = this%local(n-halo_size*2+1:n-halo_size,:,:)
end subroutine
module subroutine put_west(this)
class(exchangeable_t), intent(inout) :: this
integer :: start, ny
start = lbound(this%local,1)
ny = size(this%local,3)
if (assertions) then
!! gfortran 6.3.0 doesn't check coarray shape conformity with -fcheck=all so we verify with an assertion
call assert( shape(this%halo_east_in(1:halo_size,:,:ny)[west_neighbor]) &
== shape(this%local(start+halo_size:start+halo_size*2-1,:,:)), &
"put_west: conformable halo_east_in and local " )
end if
!dir$ pgas defer_sync
this%halo_east_in(1:halo_size,:,1:ny)[west_neighbor] = this%local(start+halo_size:start+halo_size*2-1,:,:)
end subroutine
module subroutine retrieve_east_halo(this)
class(exchangeable_t), intent(inout) :: this
integer :: n, ny
n = ubound(this%local,1)
ny = size(this%local,3)
this%local(n-halo_size+1:n,:,:) = this%halo_east_in(1:halo_size,:,1:ny)
end subroutine
module subroutine retrieve_west_halo(this)
class(exchangeable_t), intent(inout) :: this
integer :: start, ny
start = lbound(this%local,1)
ny = size(this%local,3)
this%local(start:start+halo_size-1,:,:) = this%halo_west_in(1:halo_size,:,1:ny)
end subroutine
end submodule