|
| 1 | +program fdtd_coarray_optimized |
| 2 | + use iso_fortran_env |
| 3 | + implicit none |
| 4 | + |
| 5 | + ! Parameters |
| 6 | + integer, parameter :: Ni = 32, Nj = 32, Nk = 32 |
| 7 | + integer, parameter :: num_iterations = 100 |
| 8 | + real(8), parameter :: C = 3e10, PI = 3.14159265358 |
| 9 | + real(8), parameter :: dx = C, dy = C, dz = C, dt = 0.2 |
| 10 | + real(8), parameter :: coef_B_dx = C * dt / (2 * dx), coef_B_dy = C * dt / (2 * dy), coef_B_dz = C * dt / (2 * dz) |
| 11 | + real(8), parameter :: coef_E_dx = C * dt / dx, coef_E_dy = C * dt / dy, coef_E_dz = C * dt / dz |
| 12 | + real(8), parameter :: coef_J = 4*PI*dt |
| 13 | + |
| 14 | + ! Field arrays (optimized layout for vectorization) |
| 15 | + real(8), allocatable :: Ex(:,:,:)[:], Ey(:,:,:)[:], Ez(:,:,:)[:] |
| 16 | + real(8), allocatable :: Bx(:,:,:)[:], By(:,:,:)[:], Bz(:,:,:)[:] |
| 17 | + real(8), allocatable :: Jx(:,:,:)[:], Jy(:,:,:)[:], Jz(:,:,:)[:] |
| 18 | + real(8), allocatable :: next_Ex(:,:)[:], next_Ey(:,:)[:], pred_Bx(:,:)[:], pred_By(:,:)[:] |
| 19 | + |
| 20 | + ! Local variables |
| 21 | + integer :: this_img, total_imgs, next_img, pred_img |
| 22 | + integer :: k_start, k_end, k_local |
| 23 | + integer :: idx, t |
| 24 | + integer(int64) :: start_time, end_time, rate |
| 25 | + integer :: start_i, start_j, start_k, max_i, max_j, max_k |
| 26 | + real(8) :: elapsed_time |
| 27 | + real(8) :: Tx, Ty, Tz, TT, bnd, current_time |
| 28 | + |
| 29 | + ! Coarray initialization |
| 30 | + this_img = this_image() |
| 31 | + total_imgs = num_images() |
| 32 | + next_img = merge(this_image() + 1, 1, this_image() < num_images()) |
| 33 | + pred_img = merge(this_image() - 1, num_images(), this_image() > 1) |
| 34 | + |
| 35 | + TT = 8.0 |
| 36 | + Tx = 4 * C |
| 37 | + Ty = 4 * C |
| 38 | + Tz = 4 * C |
| 39 | + current_time = min(int(TT / dt), num_iterations) |
| 40 | + |
| 41 | + bnd = Ni / 2.0 * dx |
| 42 | + |
| 43 | + start_i = floor((-Tx/4.0 + bnd) / dx) + 1 |
| 44 | + start_j = floor((-Ty/4.0 + bnd) / dy) + 1 |
| 45 | + start_k = floor((-Tz/4.0 + bnd) / dz) + 1 |
| 46 | + |
| 47 | + max_i = floor((Tx/4.0 + bnd) / dx) + 1 |
| 48 | + max_j = floor((Ty/4.0 + bnd) / dy) + 1 |
| 49 | + max_k = floor((Tz/4.0 + bnd) / dz) + 1 |
| 50 | + |
| 51 | + ! Domain decomposition |
| 52 | + call init_decomposition() |
| 53 | + |
| 54 | + ! Allocate arrays with optimized layout |
| 55 | + allocate(Ex(Ni, Nj, k_local)[*]) |
| 56 | + allocate(Ey(Ni, Nj, k_local)[*]) |
| 57 | + allocate(Ez(Ni, Nj, k_local)[*]) |
| 58 | + allocate(Bx(Ni, Nj, k_local)[*]) |
| 59 | + allocate(By(Ni, Nj, k_local)[*]) |
| 60 | + allocate(Bz(Ni, Nj, k_local)[*]) |
| 61 | + allocate(Jx(Ni, Nj, k_local)[*]) |
| 62 | + allocate(Jy(Ni, Nj, k_local)[*]) |
| 63 | + allocate(Jz(Ni, Nj, k_local)[*]) |
| 64 | + |
| 65 | + allocate(next_Ex(Ni, Nj)[*]) |
| 66 | + allocate(next_Ey(Ni, Nj)[*]) |
| 67 | + allocate(pred_Bx(Ni, Nj)[*]) |
| 68 | + allocate(pred_By(Ni, Nj)[*]) |
| 69 | + |
| 70 | + ! Initialize fields |
| 71 | + call init_fields() |
| 72 | + |
| 73 | + ! Timing and output |
| 74 | + if (this_img == 1) then |
| 75 | + print '(A, I0)', 'Running on ', total_imgs, ' images' |
| 76 | + call system_clock(count_rate=rate) |
| 77 | + call system_clock(count=start_time) |
| 78 | + end if |
| 79 | + |
| 80 | + ! Main FDTD loop |
| 81 | + do t = 1, current_time |
| 82 | + if (this_img == 1) then |
| 83 | + call init_currents(t) |
| 84 | + end if |
| 85 | + sync all |
| 86 | + |
| 87 | + call update_B_field() |
| 88 | + sync all |
| 89 | + |
| 90 | + pred_Bx(:,:) = Bx(:, :, k_local)[pred_img] |
| 91 | + pred_By(:,:) = By(:, :, k_local)[pred_img] |
| 92 | + sync all |
| 93 | + |
| 94 | + call update_E_field() |
| 95 | + sync all |
| 96 | + |
| 97 | + next_Ex(:,:) = Ex(:, :, 1)[next_img] |
| 98 | + next_Ey(:,:) = Ey(:, :, 1)[next_img] |
| 99 | + sync all |
| 100 | + |
| 101 | + call update_B_field() |
| 102 | + sync all |
| 103 | + |
| 104 | + end do |
| 105 | + |
| 106 | + Jx = 0.0 |
| 107 | + Jy = 0.0 |
| 108 | + Jz = 0.0 |
| 109 | + sync all |
| 110 | + |
| 111 | + do t = current_time + 1, num_iterations |
| 112 | + call update_B_field() |
| 113 | + sync all |
| 114 | + |
| 115 | + pred_Bx(:,:) = Bx(:, :, k_local)[pred_img] |
| 116 | + pred_By(:,:) = By(:, :, k_local)[pred_img] |
| 117 | + sync all |
| 118 | + |
| 119 | + call update_E_field() |
| 120 | + sync all |
| 121 | + |
| 122 | + next_Ex(:,:) = Ex(:, :, 1)[next_img] |
| 123 | + next_Ey(:,:) = Ey(:, :, 1)[next_img] |
| 124 | + sync all |
| 125 | + |
| 126 | + call update_B_field() |
| 127 | + sync all |
| 128 | + |
| 129 | + end do |
| 130 | + |
| 131 | + sync all |
| 132 | + ! Final timing and cleanup |
| 133 | + if (this_img == 1) then |
| 134 | + call system_clock(count=end_time) |
| 135 | + elapsed_time = real(end_time - start_time)/real(rate) |
| 136 | + print '(A, F0.2, A)', 'Total execution time: ', elapsed_time, ' seconds' |
| 137 | + end if |
| 138 | + |
| 139 | + sync all |
| 140 | + if ((this_image() == 1)) then !.and. (Nk <= 16)) then |
| 141 | + call print_full_E_slice() |
| 142 | + end if |
| 143 | + |
| 144 | + deallocate(Ex, Ey, Ez, Bx, By, Bz, Jx, Jy, Jz) |
| 145 | + deallocate(next_Ex, next_Ey, pred_Bx, pred_By) |
| 146 | + |
| 147 | +contains |
| 148 | + !=============================================================== |
| 149 | + subroutine init_decomposition |
| 150 | + integer :: remainder, offset |
| 151 | + |
| 152 | + remainder = mod(Nk, total_imgs) |
| 153 | + k_local = Nk / total_imgs |
| 154 | + |
| 155 | + if (this_img <= remainder) then |
| 156 | + k_local = k_local + 1 |
| 157 | + offset = (this_img - 1)*k_local |
| 158 | + else |
| 159 | + offset = remainder*(k_local + 1) + (this_img - remainder - 1)*k_local |
| 160 | + end if |
| 161 | + |
| 162 | + k_start = offset + 1 |
| 163 | + k_end = offset + k_local |
| 164 | + end subroutine init_decomposition |
| 165 | + |
| 166 | + !=============================================================== |
| 167 | + subroutine init_fields |
| 168 | + Ex = 0.0 |
| 169 | + Ey = 0.0 |
| 170 | + Ez = 0.0 |
| 171 | + next_Ex = 0.0 |
| 172 | + next_Ey = 0.0 |
| 173 | + pred_Bx = 0.0 |
| 174 | + pred_By = 0.0 |
| 175 | + Bx = 0.0 |
| 176 | + By = 0.0 |
| 177 | + Bz = 0.0 |
| 178 | + Jx = 0.0 |
| 179 | + Jy = 0.0 |
| 180 | + Jz = 0.0 |
| 181 | + end subroutine init_fields |
| 182 | + |
| 183 | + !=============================================================== |
| 184 | + subroutine init_currents(this_t) |
| 185 | + integer, intent(in) :: this_t |
| 186 | + integer :: i, j, k |
| 187 | + integer :: this_cur_img |
| 188 | + real(8) :: value |
| 189 | + |
| 190 | + do k = start_k, max_k |
| 191 | + do j = start_j, max_j |
| 192 | + do i = start_i, max_i |
| 193 | + this_cur_img = ceiling(real(k) / real(k_local)) |
| 194 | + value = (sin(2.0 * PI * this_t * dt / TT)) & |
| 195 | + * (cos(2.0 * PI * (i-1) * dx / Tx)**2) & |
| 196 | + * (cos(2.0 * PI * (j-1) * dy / Ty)**2) & |
| 197 | + * (cos(2.0 * PI * (k-1) * dz / Tz)**2) |
| 198 | + Jx(i,j,k - (this_cur_img - 1) * k_local)[this_cur_img] = value |
| 199 | + Jy(i,j,k - (this_cur_img - 1) * k_local)[this_cur_img] = value |
| 200 | + Jz(i,j,k - (this_cur_img - 1) * k_local)[this_cur_img] = value |
| 201 | + end do |
| 202 | + end do |
| 203 | + end do |
| 204 | + end subroutine init_currents |
| 205 | + |
| 206 | + !=============================================================== |
| 207 | + subroutine update_B_field |
| 208 | + integer :: ip, jp, kp |
| 209 | + integer :: i, j, k |
| 210 | + |
| 211 | + do k = 1, k_local - 1 |
| 212 | + do j = 1, Nj |
| 213 | + jp = merge(j+1, 1, j < Nj) |
| 214 | + do i = 1, Ni |
| 215 | + ip = merge(i+1, 1, i < Ni) |
| 216 | + |
| 217 | + Bx(i,j,k) = Bx(i,j,k) + coef_B_dz * (Ey(i,j,k+1) - Ey(i,j,k)) - & |
| 218 | + coef_B_dy * (Ez(i,jp,k) - Ez(i,j,k)) |
| 219 | + |
| 220 | + By(i,j,k) = By(i,j,k) + coef_B_dx * (Ez(ip,j,k) - Ez(i,j,k)) - & |
| 221 | + coef_B_dz * (Ex(i,j,k+1) - Ex(i,j,k)) |
| 222 | + |
| 223 | + Bz(i,j,k) = Bz(i,j,k) + coef_B_dy * (Ex(i,jp,k) - Ex(i,j,k)) - & |
| 224 | + coef_B_dx * (Ey(ip,j,k) - Ey(i,j,k)) |
| 225 | + end do |
| 226 | + end do |
| 227 | + end do |
| 228 | + do j = 1, Nj |
| 229 | + jp = merge(j+1, 1, j < Nj) |
| 230 | + do i = 1, Ni |
| 231 | + ip = merge(i+1, 1, i < Ni) |
| 232 | + |
| 233 | + Bx(i,j,k_local) = Bx(i,j,k_local) + coef_B_dz * (next_Ey(i,j) - Ey(i,j,k_local)) - & |
| 234 | + coef_B_dy * (Ez(i,jp,k_local) - Ez(i,j,k_local)) |
| 235 | + |
| 236 | + By(i,j,k_local) = By(i,j,k_local) + coef_B_dx * (Ez(ip,j,k_local) - Ez(i,j,k)) - & |
| 237 | + coef_B_dz * (next_Ex(i,j) - Ex(i,j,k_local)) |
| 238 | + |
| 239 | + Bz(i,j,k_local) = Bz(i,j,k_local) + coef_B_dy * (Ex(i,jp,k_local) - Ex(i,j,k_local)) - & |
| 240 | + coef_B_dx * (Ey(ip,j,k_local) - Ey(i,j,k_local)) |
| 241 | + end do |
| 242 | + end do |
| 243 | + |
| 244 | + end subroutine update_B_field |
| 245 | + |
| 246 | + !=============================================================== |
| 247 | + subroutine update_E_field |
| 248 | + integer :: im, jm, km |
| 249 | + integer :: i, j, k |
| 250 | + |
| 251 | + do j = 1, Nj |
| 252 | + jm = merge(j-1, Nj, j > 1) |
| 253 | + do i = 1, Ni |
| 254 | + im = merge(i-1, Ni, i > 1) |
| 255 | + |
| 256 | + Ex(i,j,1) = Ex(i,j,1) - coef_J * Jx(i,j,1) + & |
| 257 | + coef_E_dy * (Bz(i,j,1) - Bz(i,jm,1)) - & |
| 258 | + coef_E_dz * (By(i,j,1) - pred_By(i,j)) |
| 259 | + |
| 260 | + Ey(i,j,1) = Ey(i,j,1) - coef_J * Jy(i,j,1) + & |
| 261 | + coef_E_dz * (Bx(i,j,1) - pred_Bx(i,j)) - & |
| 262 | + coef_E_dx * (Bz(i,j,1) - Bz(im,j,1)) |
| 263 | + |
| 264 | + Ez(i,j,1) = Ez(i,j,1) - coef_J * Jz(i,j,1) + & |
| 265 | + coef_E_dx * (By(i,j,1) - By(im,j,1)) - & |
| 266 | + coef_E_dy * (Bx(i,j,1) - Bx(i,jm,1)) |
| 267 | + end do |
| 268 | + end do |
| 269 | + do k = 2, k_local |
| 270 | + do j = 1, Nj |
| 271 | + jm = merge(j-1, Nj, j > 1) |
| 272 | + do i = 1, Ni |
| 273 | + im = merge(i-1, Ni, i > 1) |
| 274 | + |
| 275 | + Ex(i,j,k) = Ex(i,j,k) - coef_J * Jx(i,j,k) + & |
| 276 | + coef_E_dy * (Bz(i,j,k) - Bz(i,jm,k)) - & |
| 277 | + coef_E_dz * (By(i,j,k) - By(i,j,k-1)) |
| 278 | + |
| 279 | + Ey(i,j,k) = Ey(i,j,k) - coef_J * Jy(i,j,k) + & |
| 280 | + coef_E_dz * (Bx(i,j,k) - Bx(i,j,k-1)) - & |
| 281 | + coef_E_dx * (Bz(i,j,k) - Bz(im,j,k)) |
| 282 | + |
| 283 | + Ez(i,j,k) = Ez(i,j,k) - coef_J * Jz(i,j,k) + & |
| 284 | + coef_E_dx * (By(i,j,k) - By(im,j,k)) - & |
| 285 | + coef_E_dy * (Bx(i,j,k) - Bx(i,jm,k)) |
| 286 | + end do |
| 287 | + end do |
| 288 | + end do |
| 289 | + end subroutine update_E_field |
| 290 | + |
| 291 | + !=============================================================== |
| 292 | +subroutine print_full_E_slice() |
| 293 | + integer :: img, ik, ij |
| 294 | + do ij = Nj/2-4, Nj/2+5 |
| 295 | + do ik = Ni/2-4, Ni/2+5 |
| 296 | + img = ceiling(real(Nk/2+1) / real(k_local)) |
| 297 | + write(*, '(F12.5)', advance='no') Ex(ik,ij,Nk/2+1 - (img - 1) * k_local)[img] |
| 298 | + end do |
| 299 | + print * |
| 300 | + end do |
| 301 | + |
| 302 | +end subroutine print_full_E_slice |
| 303 | +end program fdtd_coarray_optimized |
0 commit comments