Octopus
phase.F90
Go to the documentation of this file.
1!! Copyright (C) 2009 X. Andrade
2!! Copyright (C) 2024 N. Tancogne-Dejean
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module phase_oct_m
23 use accel_oct_m
24 use batch_oct_m
27 use debug_oct_m
31 use global_oct_m
32 use grid_oct_m
35 use math_oct_m
36 use mesh_oct_m
38 use mpi_oct_m
40 use space_oct_m
44 use types_oct_m
46
47 implicit none
48
49 private
50
51 public :: &
52 phase_t, &
54
85 type phase_t
86 private
87 complex(real64), allocatable :: phase(:, :)
90 complex(real64), public, allocatable :: phase_corr(:,:)
93 complex(real64), allocatable :: phase_k(:, :)
95 complex(real64), allocatable :: phase_corr_k(:,:)
96 complex(real64), allocatable :: vp_phase(:)
97 complex(real64), allocatable :: vp_phase_corr(:)
98 complex(real64), allocatable :: phase_spiral(:,:)
101 type(accel_mem_t) :: buff_phase
102 type(accel_mem_t) :: buff_phase_spiral
103 type(accel_mem_t), public :: buff_phase_corr
104 integer :: buff_phase_qn_start
105 real(real64), public, pointer :: spin(:,:,:) => null()
106 contains
107 procedure :: init => phase_init_phases
108
109 procedure :: update => phase_update_phases
110
111 procedure :: end => phase_end
112
113 procedure :: set_phase_corr => phase_set_phase_corr
114
115 procedure :: unset_phase_corr => phase_unset_phase_corr
116
117 procedure :: apply_to => phase_apply_batch
118
119 procedure :: apply_to_single => phase_apply_mf
120
121 procedure :: apply_phase_spiral => phase_phase_spiral
122
123 procedure :: is_allocated => phase_is_allocated
124
125 procedure :: copy_and_set_phase => phase_copy_and_set_phase
126 end type phase_t
127
128contains
129
130 ! ---------------------------------------------------------
132 subroutine phase_init_phases(phase, gr, kpt, kpoints, d, space)
133 class(phase_t), intent(inout) :: phase
134 class(mesh_t), intent(in) :: gr
135 type(distributed_t), intent(in) :: kpt
136 type(kpoints_t), intent(in) :: kpoints
137 type(states_elec_dim_t), intent(in) :: d
138 type(space_t), intent(in) :: space
139
140 integer :: ip, ik, sp
141 integer(int64) :: ip_inner_global
142 real(real64) :: kpoint(space%dim), x_global(space%dim)
143
144 push_sub(phase_init_phases)
145
146 ! no e^ik phase needed for Gamma-point-only periodic calculations
147 ! unless for velocity-gauge for lasers
148 if (accel_is_enabled()) then
149 phase%buff_phase_qn_start = kpt%start
150 end if
151 if(kpoints%gamma_only()) then
152 pop_sub(phase_init_phases)
153 return
154 end if
155
156 safe_allocate(phase%phase(1:gr%np_part, kpt%start:kpt%end))
157 safe_allocate(phase%phase_corr(gr%np+1:gr%np_part, kpt%start:kpt%end))
158 !$omp parallel private(ip)
159 do ik = kpt%start, kpt%end
160 !$omp do
161 do ip = gr%np + 1, gr%np_part
162 phase%phase_corr(ip, ik) = m_one
163 end do
164 !$omp end do nowait
165 end do
166 !$omp end parallel
167
168 ! Only when gr is a grid_t type, we can access gr%der
169 select type(gr)
170 class is(grid_t)
171 if (gr%der%boundaries%spiralBC) then
172 sp = gr%np
173 if (gr%parallel_in_domains) sp = gr%np + gr%pv%np_ghost
174
175 ! We decided to allocate the array from 1:np_part-sp as this is less error prone when passing
176 ! the array to other routines, or in particular creating a C-style pointer from phase_spiral(1,1).
177 ! We will also update phase_corr and possible other similar arrays.
178
179 safe_allocate(phase%phase_spiral(1:gr%np_part-sp, 1:2))
181 ! loop over boundary points
182 do ip = sp + 1, gr%np_part
183 ! get corresponding inner point
184 ip_inner_global = mesh_periodic_point(gr, space, ip)
185 x_global = mesh_x_global(gr, ip_inner_global)
186 phase%phase_spiral(ip-sp, 1) = &
187 exp(m_zi * sum((gr%x(1:space%dim, ip)-x_global(1:space%dim)) * gr%der%boundaries%spiral_q(1:space%dim)))
188 phase%phase_spiral(ip-sp, 2) = &
189 exp(-m_zi * sum((gr%x(1:space%dim, ip)-x_global(1:space%dim)) * gr%der%boundaries%spiral_q(1:space%dim)))
190 end do
193 call accel_create_buffer(phase%buff_phase_spiral, accel_mem_read_only, type_cmplx, (gr%np_part-sp)*2)
194 call accel_write_buffer(phase%buff_phase_spiral, gr%np_part-sp, 2, phase%phase_spiral)
195 end if
196 end if
197 class default
198 ! Do nothing
199 end select
201
202 kpoint(1:space%dim) = m_zero
203
204 sp = gr%np
205 if (gr%parallel_in_domains) sp = gr%np + gr%pv%np_ghost
207 !$omp parallel private(ip, ip_inner_global, x_global, kpoint)
208 do ik = kpt%start, kpt%end
209 kpoint(1:space%dim) = kpoints%get_point(d%get_kpoint_index(ik))
210 !$omp do
211 do ip = 1, gr%np_part
212 phase%phase(ip, ik) = exp(-m_zi * sum(gr%x(1:space%dim, ip) * kpoint(1:space%dim)))
213 end do
214 !$omp end do
215
216 ! loop over boundary points
217 !$omp do
218 do ip = sp + 1, gr%np_part
219 ! get corresponding inner point
220 ip_inner_global = mesh_periodic_point(gr, space, ip)
221
222 ! compute phase correction from global coordinate (opposite sign!)
223 x_global = mesh_x_global(gr, ip_inner_global)
224 phase%phase_corr(ip, ik) = phase%phase(ip, ik)* &
225 exp(m_zi * sum(x_global(1:space%dim) * kpoint(1:space%dim)))
226 end do
227 !$omp end do nowait
228 end do
229 !$omp end parallel
230
231 if (accel_is_enabled()) then
232 call accel_create_buffer(phase%buff_phase, accel_mem_read_write, type_cmplx, gr%np_part*kpt%nlocal())
233 call accel_write_buffer(phase%buff_phase, gr%np_part, kpt%nlocal(), phase%phase)
234 call accel_create_buffer(phase%buff_phase_corr, accel_mem_read_write, type_cmplx, (gr%np_part - gr%np)*kpt%nlocal())
235 call accel_write_buffer(phase%buff_phase_corr, gr%np_part - gr%np, kpt%nlocal(), phase%phase_corr)
236 end if
237
238 pop_sub(phase_init_phases)
239 end subroutine phase_init_phases
240
241 ! ----------------------------------------------------------------------------------
243 subroutine phase_update_phases(phase, mesh, kpt, kpoints, d, space, uniform_vector_potential)
244 class(phase_t), intent(inout) :: phase
245 class(mesh_t), intent(in) :: mesh
246 type(distributed_t), intent(in) :: kpt
247 type(kpoints_t), intent(in) :: kpoints
248 type(states_elec_dim_t), intent(in) :: d
249 type(space_t), intent(in) :: space
250 real(real64), allocatable, intent(in) :: uniform_vector_potential(:)
251
252 integer :: ik, ip, sp
253 integer(int64), dimension(2) :: np, gsize, bsize
254 integer(int64) :: ip_inner_global
255 real(real64) :: kpoint(space%dim)
256 real(real64), allocatable :: x_global(:,:), kpt_vec_pot(:,:)
257 type(accel_mem_t) :: buff_vec_pot, buff_x_global, buff_x
258 type(accel_kernel_t), save, target :: kernels(3)
259 type(accel_kernel_t), pointer :: kernel
260 character(len=128) :: kernel_name
261 real(real64) :: tmp_sum
262
263 if (.not. allocated(uniform_vector_potential)) return
264
265 push_sub_with_profile(phase_update_phases)
266
267
268 if (.not. allocated(phase%phase)) then
269 safe_allocate(phase%phase(1:mesh%np_part, kpt%start:kpt%end))
270 if (accel_is_enabled()) then
271 call accel_create_buffer(phase%buff_phase, accel_mem_read_write, type_cmplx, &
272 mesh%np_part*kpt%nlocal())
273 end if
274 end if
275
276 if (.not. allocated(phase%phase_corr)) then
277 safe_allocate(phase%phase_corr(mesh%np+1:mesh%np_part, kpt%start:kpt%end))
278 if (accel_is_enabled()) then
279 call accel_create_buffer(phase%buff_phase_corr, accel_mem_read_write, type_cmplx, &
280 (mesh%np_part - mesh%np)*kpt%nlocal())
281 end if
282 end if
283
284 ! TODO: We should not recompute this every time-step. We should store it.
285
286 ! loop over boundary points
287 sp = mesh%np
288 ! skip ghost points
289 if (mesh%parallel_in_domains) sp = mesh%np + mesh%pv%np_ghost
290
291 safe_allocate(x_global(1:space%dim,(sp + 1):mesh%np_part))
292
293 !$omp parallel do schedule(static) private(ip_inner_global)
294 do ip = sp + 1, mesh%np_part
295 ! get corresponding inner point
296 ip_inner_global = mesh_periodic_point(mesh, space, ip)
297 ! compute the difference between the global coordinate and the local coordinate
298 x_global(:,ip) = mesh_x_global(mesh, ip_inner_global) - mesh%x(1:space%dim, ip)
299 end do
300
301
302 if (.not. accel_is_enabled()) then
303 ! Factorize exp(-i x.(k+A)) = exp(-i x.k) * exp(-i x.A(t)). The k-only factor is static and
304 ! computed once; the A(t) factor is the same for all k-points, so only ~np_part sincos are
305 ! needed per step instead of np_part*n_kpoints.
306 if (.not. allocated(phase%phase_k)) then
307 safe_allocate(phase%phase_k(1:mesh%np_part, kpt%start:kpt%end))
308 safe_allocate(phase%phase_corr_k(sp + 1:mesh%np_part, kpt%start:kpt%end))
309 safe_allocate(phase%vp_phase(1:mesh%np_part))
310 safe_allocate(phase%vp_phase_corr(sp + 1:mesh%np_part))
311 !$omp parallel private(ik, ip, kpoint, tmp_sum)
312 do ik = kpt%start, kpt%end
313 kpoint(1:space%dim) = kpoints%get_point(d%get_kpoint_index(ik))
314 !$omp do schedule(static)
315 do ip = 1, mesh%np_part
316 tmp_sum = sum(mesh%x(1:space%dim, ip)*kpoint(1:space%dim))
317 phase%phase_k(ip, ik) = cmplx(cos(tmp_sum), -sin(tmp_sum), real64)
318 end do
319 !$omp end do nowait
320 !$omp do schedule(static)
321 do ip = sp + 1, mesh%np_part
322 tmp_sum = sum(x_global(1:space%dim, ip)*kpoint(1:space%dim))
323 phase%phase_corr_k(ip, ik) = cmplx(cos(tmp_sum), sin(tmp_sum), real64)
324 end do
325 !$omp end do nowait
326 end do
327 !$omp end parallel
328 end if
329
330 !$omp parallel private(ik, ip, tmp_sum)
331 ! k-independent time-dependent factor exp(-i x.A(t)) (recomputed each step)
332 !$omp do schedule(static)
333 do ip = 1, mesh%np_part
334 tmp_sum = sum(mesh%x(1:space%dim, ip)*uniform_vector_potential(1:space%dim))
335 phase%vp_phase(ip) = cmplx(cos(tmp_sum), -sin(tmp_sum), real64)
336 end do
337 !$omp end do
338 !$omp do schedule(static)
339 do ip = sp + 1, mesh%np_part
340 tmp_sum = sum(x_global(1:space%dim, ip)*uniform_vector_potential(1:space%dim))
341 phase%vp_phase_corr(ip) = cmplx(cos(tmp_sum), sin(tmp_sum), real64)
342 end do
343 !$omp end do
344
345 ! combine static and time-dependent factors (contiguous in ip)
346 do ik = kpt%start, kpt%end
347 !$omp do schedule(static)
348 do ip = 1, mesh%np_part
349 phase%phase(ip, ik) = phase%phase_k(ip, ik) * phase%vp_phase(ip)
350 end do
351 !$omp end do nowait
352 !$omp do schedule(static)
353 do ip = sp + 1, mesh%np_part
354 phase%phase_corr(ip, ik) = phase%phase_corr_k(ip, ik) * phase%vp_phase_corr(ip)
355 end do
356 !$omp end do nowait
357 end do
358 !$omp end parallel
359
360 else !accel_is enabled
361
362 call accel_create_buffer(buff_vec_pot, accel_mem_read_only, type_float, space%dim*kpt%nlocal())
363 safe_allocate(kpt_vec_pot(1:space%dim,kpt%start:kpt%end))
364 do ik = kpt%start, kpt%end
365 kpoint(1:space%dim) = kpoints%get_point(d%get_kpoint_index(ik))
366 kpt_vec_pot(1:space%dim, ik) = kpoint(1:space%dim) + uniform_vector_potential(1:space%dim)
367 end do
368 call accel_write_buffer(buff_vec_pot, space%dim, kpt%nlocal(), kpt_vec_pot, async=.true.)
369
370 ! Note: this should be globally stored
371 call accel_create_buffer(buff_x, accel_mem_read_only, type_float, space%dim*(mesh%np_part))
372 call accel_write_buffer(buff_x, space%dim, mesh%np_part, mesh%x, async=.true.)
373
374 call accel_create_buffer(buff_x_global, accel_mem_read_only, type_float, space%dim*(mesh%np_part-sp))
375 call accel_write_buffer(buff_x_global, space%dim, mesh%np_part-sp, x_global(1:space%dim,(sp + 1):mesh%np_part), async=.true.)
376
377 write(kernel_name, '(a,i1,a)') 'update_phases<double, Dim::D', space%dim, '>'
378 kernel => kernels(space%dim)
379 call accel_kernel_start_call(kernel, 'phase.cu', trim(kernel_name))
380
381 call accel_set_kernel_arg(kernel, 0, mesh%np)
382 call accel_set_kernel_arg(kernel, 1, mesh%np_part)
383 call accel_set_kernel_arg(kernel, 2, kpt%start)
384 call accel_set_kernel_arg(kernel, 3, kpt%end)
385 call accel_set_kernel_arg(kernel, 4, sp)
386 call accel_set_kernel_arg(kernel, 5, buff_vec_pot)
387 call accel_set_kernel_arg(kernel, 6, buff_x)
388 call accel_set_kernel_arg(kernel, 7, buff_x_global)
389 call accel_set_kernel_arg(kernel, 8, phase%buff_phase)
390 call accel_set_kernel_arg(kernel, 9, phase%buff_phase_corr)
391
392 ! Compute the grid size
393 np = (/mesh%np_part, kpt%nlocal()/)
394 bsize = (/accel_kernel_block_size(kernel), 1/)
395 call accel_grid_size(np, bsize, gsize)
396
397 call accel_kernel_run(kernel, gsize, bsize)
398
399 call accel_read_buffer(phase%buff_phase, mesh%np_part, kpt%nlocal(), phase%phase, async=.true.)
400 call accel_read_buffer(phase%buff_phase_corr, mesh%np_part - mesh%np, kpt%nlocal(), phase%phase_corr)
401
402 call accel_free_buffer(buff_vec_pot)
403 call accel_free_buffer(buff_x)
404 call accel_free_buffer(buff_x_global)
405 safe_deallocate_a(kpt_vec_pot)
406 end if
407
408 safe_deallocate_a(x_global)
409
410 pop_sub_with_profile(phase_update_phases)
411 end subroutine phase_update_phases
412
413 ! ----------------------------------------------------------------------------------
415 subroutine phase_end(phase)
416 class(phase_t), intent(inout) :: phase
417
418 push_sub(phase_end)
419
420 if (phase%is_allocated() .and. accel_is_enabled()) then
421 call accel_free_buffer(phase%buff_phase)
422 call accel_free_buffer(phase%buff_phase_corr)
423 end if
424
425 if (allocated(phase%phase_spiral) .and. accel_is_enabled()) then
426 call accel_free_buffer(phase%buff_phase_spiral)
427 end if
428
429 safe_deallocate_a(phase%phase)
430 safe_deallocate_a(phase%phase_corr)
431 safe_deallocate_a(phase%phase_k)
432 safe_deallocate_a(phase%phase_corr_k)
433 safe_deallocate_a(phase%vp_phase)
434 safe_deallocate_a(phase%vp_phase_corr)
435 safe_deallocate_a(phase%phase_spiral)
436
437 pop_sub(phase_end)
438 end subroutine phase_end
439
440 ! ----------------------------------------------------------------------------------
442 subroutine phase_accel_rebuild(phase, mesh, kpt)
443 class(phase_t), intent(inout) :: phase
444 class(mesh_t), intent(in) :: mesh
445 type(distributed_t), intent(in) :: kpt
446
447 integer :: nlocal
448
449 push_sub(phase_accel_rebuild)
450
451 if (.not. accel_is_enabled()) then
452 pop_sub(phase_accel_rebuild)
453 return
454 end if
455
456 phase%buff_phase_qn_start = kpt%start
457
458 call accel_detach_buffer(phase%buff_phase)
459 call accel_detach_buffer(phase%buff_phase_corr)
460 call accel_detach_buffer(phase%buff_phase_spiral)
461
462 if (allocated(phase%phase)) then
463 assert(size(phase%phase, 1) == mesh%np_part)
464 nlocal = ubound(phase%phase, dim=2) - lbound(phase%phase, dim=2) + 1
465 call accel_create_buffer(phase%buff_phase, accel_mem_read_write, type_cmplx, size(phase%phase, 1)*nlocal)
466 call accel_write_buffer(phase%buff_phase, size(phase%phase, 1), nlocal, phase%phase)
467 end if
468
469 if (allocated(phase%phase_corr)) then
470 assert(size(phase%phase_corr, 1) == mesh%np_part - mesh%np)
471 nlocal = ubound(phase%phase_corr, dim=2) - lbound(phase%phase_corr, dim=2) + 1
472 call accel_create_buffer(phase%buff_phase_corr, accel_mem_read_write, type_cmplx, &
473 size(phase%phase_corr, 1)*nlocal)
474 call accel_write_buffer(phase%buff_phase_corr, size(phase%phase_corr, 1), nlocal, phase%phase_corr)
475 end if
476
477 if (allocated(phase%phase_spiral)) then
478 call accel_create_buffer(phase%buff_phase_spiral, accel_mem_read_only, type_cmplx, &
479 size(phase%phase_spiral, 1)*size(phase%phase_spiral, 2))
480 call accel_write_buffer(phase%buff_phase_spiral, size(phase%phase_spiral, 1), &
481 size(phase%phase_spiral, 2), phase%phase_spiral)
482 end if
483
484 pop_sub(phase_accel_rebuild)
485 end subroutine phase_accel_rebuild
486
487 ! ----------------------------------------------------------------------------------
489 !
490 subroutine phase_set_phase_corr(phase, mesh, psib, async)
491 class(phase_t), intent(in) :: phase
492 class(mesh_t), intent(in) :: mesh
493 type(wfs_elec_t), intent(inout) :: psib
494 logical, optional, intent(in) :: async
495
496
497 logical :: phase_correction
498
499 push_sub(phase_set_phase_corr)
500
501 ! check if we only want a phase correction for the boundary points
502 phase_correction = phase%is_allocated()
503
504 !We apply the phase only to np points, and the phase for the np+1 to np_part points
505 !will be treated as a phase correction in the Hamiltonian
506 if (phase_correction) then
507 call phase%apply_to(mesh, mesh%np, .false., psib, async=async)
508 end if
509
511 end subroutine phase_set_phase_corr
512
513 ! ----------------------------------------------------------------------------------
515 !
516 subroutine phase_unset_phase_corr(phase, mesh, psib, async)
517 class(phase_t), intent(in) :: phase
518 class(mesh_t), intent(in) :: mesh
519 type(wfs_elec_t), intent(inout) :: psib
520 logical, optional, intent(in) :: async
521
522 logical :: phase_correction
523
524 push_sub(phase_unset_phase_corr)
525
526 ! check if we only want a phase correction for the boundary points
527 phase_correction = phase%is_allocated()
528
529 !We apply the phase only to np points, and the phase for the np+1 to np_part points
530 !will be treated as a phase correction in the Hamiltonian
531 if (phase_correction) then
532 call phase%apply_to(mesh, mesh%np, .true., psib, async=async)
533 end if
534
536 end subroutine phase_unset_phase_corr
538 ! ---------------------------------------------------------------------------------------
540 !
541 subroutine phase_apply_batch(this, mesh, np, conjugate, psib, src, async)
542 class(phase_t), intent(in) :: this
543 class(mesh_t), intent(in) :: mesh
544 integer, intent(in) :: np
545 logical, intent(in) :: conjugate
546 type(wfs_elec_t), target, intent(inout) :: psib
547 type(wfs_elec_t), optional, target, intent(in) :: src
548 logical, optional, intent(in) :: async
549
550 integer :: ip, ii, sp
551 type(wfs_elec_t), pointer :: src_
552 complex(real64) :: phase
553 integer(int64), dimension(3) :: gsizes, bsizes
554 type(accel_kernel_t), save :: ker_phase
555
556 push_sub(phase_apply_batch)
557 call profiling_in("PHASE_APPLY_BATCH")
558
559 call profiling_count_operations(6*np*psib%nst_linear)
560
561 assert(np <= mesh%np_part)
562 assert(psib%type() == type_cmplx)
563 assert(psib%ik >= lbound(this%phase, dim=2))
564 assert(psib%ik <= ubound(this%phase, dim=2))
565
566 src_ => psib
567 if (present(src)) src_ => src
568
569 assert(src_%has_phase .eqv. conjugate)
570 assert(src_%ik == psib%ik)
571 assert(src_%type() == type_cmplx)
572
573 ! We want to skip the ghost points for setting the phase
574 sp = min(np, mesh%np)
575 if (np > mesh%np .and. mesh%parallel_in_domains) sp = mesh%np + mesh%pv%np_ghost
576
577 select case (psib%status())
578 case (batch_packed)
579
580 if (conjugate) then
581
582 !$omp parallel private(ii, phase)
583 !$omp do
584 do ip = 1, min(mesh%np, np)
585 phase = conjg(this%phase(ip, psib%ik))
586 !$omp simd
587 do ii = 1, psib%nst_linear
588 psib%zff_pack(ii, ip) = phase*src_%zff_pack(ii, ip)
589 end do
590 end do
591 !$omp end do nowait
592
593 ! Boundary points, if requested
594 !$omp do
595 do ip = sp+1, np
596 phase = conjg(this%phase(ip, psib%ik))
597 !$omp simd
598 do ii = 1, psib%nst_linear
599 psib%zff_pack(ii, ip) = phase*src_%zff_pack(ii, ip)
600 end do
601 end do
602 !$omp end parallel
603
604 else
605
606 !$omp parallel private(ii, phase)
607 !$omp do
608 do ip = 1, min(mesh%np, np)
609 phase = this%phase(ip, psib%ik)
610 !$omp simd
611 do ii = 1, psib%nst_linear
612 psib%zff_pack(ii, ip) = phase*src_%zff_pack(ii, ip)
613 end do
614 end do
615 !$omp end do nowait
616
617 ! Boundary points, if requested
618 !$omp do
619 do ip = sp+1, np
620 phase = this%phase(ip, psib%ik)
621 !$omp simd
622 do ii = 1, psib%nst_linear
623 psib%zff_pack(ii, ip) = phase*src_%zff_pack(ii, ip)
624 end do
625 end do
626 !$omp end parallel
627
628 end if
629
630 case (batch_not_packed)
631
632 if (conjugate) then
633
634 !$omp parallel private(ii, ip)
635 do ii = 1, psib%nst_linear
636 !$omp do simd
637 do ip = 1, min(mesh%np, np)
638 psib%zff_linear(ip, ii) = conjg(this%phase(ip, psib%ik))*src_%zff_linear(ip, ii)
639 end do
640 !$omp end do simd nowait
641
642 ! Boundary points, if requested
643 !$omp do simd
644 do ip = sp+1, np
645 psib%zff_linear(ip, ii) = conjg(this%phase(ip, psib%ik))*src_%zff_linear(ip, ii)
646 end do
647 !$omp end do simd nowait
648 end do
649 !$omp end parallel
650
651 else
652 !$omp parallel private(ii, ip)
653 do ii = 1, psib%nst_linear
654 !$omp do simd
655 do ip = 1, min(mesh%np, np)
656 psib%zff_linear(ip, ii) = this%phase(ip, psib%ik)*src_%zff_linear(ip, ii)
657 end do
658 !$omp end do simd nowait
659
660 ! Boundary points, if requested
661 !$omp do simd
662 do ip = sp+1, np
663 psib%zff_linear(ip, ii) = this%phase(ip, psib%ik)*src_%zff_linear(ip, ii)
664 end do
665 !$omp end do simd nowait
666
667 end do
668 !$omp end parallel
669
670 end if
671
673 call accel_kernel_start_call(ker_phase, 'phase.cu', 'phase_hamiltonian<double>')
674
675 if (conjugate) then
676 call accel_set_kernel_arg(ker_phase, 0, 1_4)
677 else
678 call accel_set_kernel_arg(ker_phase, 0, 0_4)
679 end if
680
681 call accel_set_kernel_arg(ker_phase, 1, (psib%ik - this%buff_phase_qn_start)*mesh%np_part)
682 call accel_set_kernel_arg(ker_phase, 2, np)
683 call accel_set_kernel_arg(ker_phase, 3, this%buff_phase)
684 call accel_set_kernel_arg(ker_phase, 4, src_%ff_device)
685 call accel_set_kernel_arg(ker_phase, 5, log2(int(src_%pack_size(1), int32)))
686 call accel_set_kernel_arg(ker_phase, 6, psib%ff_device)
687 call accel_set_kernel_arg(ker_phase, 7, log2(int(psib%pack_size(1), int32)))
688
689 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
690 call accel_grid_size_extend_dim(int(np, int64), psib%pack_size(1), gsizes, bsizes, ker_phase)
691
692 call accel_kernel_run(ker_phase, gsizes, bsizes)
693
694 if(.not. optional_default(async, .false.)) call accel_finish()
695 end select
696
697 psib%has_phase = .not. conjugate
698
699 call profiling_out("PHASE_APPLY_BATCH")
700 pop_sub(phase_apply_batch)
701 end subroutine phase_apply_batch
702
708 !
709 subroutine phase_apply_mf(this, psi, np, dim, ik, conjugate)
710 class(phase_t), intent(in) :: this
711 complex(real64), intent(inout) :: psi(:, :)
712 integer, intent(in) :: np
713 integer, intent(in) :: dim
714 integer, intent(in) :: ik
715 logical, intent(in) :: conjugate
716
717 integer :: idim, ip
718
719 push_sub(phase_apply_mf)
720
721 assert(ik >= lbound(this%phase, dim=2))
722 assert(ik <= ubound(this%phase, dim=2))
723
724 call profiling_in("PHASE_APPLY_SINGLE")
725
726 if (conjugate) then
727 ! Apply the phase that contains both the k-point and vector-potential terms.
728 do idim = 1, dim
729 !$omp parallel do
730 do ip = 1, np
731 psi(ip, idim) = conjg(this%phase(ip, ik))*psi(ip, idim)
732 end do
733 !$omp end parallel do
734 end do
735 else
736 ! Apply the conjugate of (i.e. remove) the phase that contains both the k-point and vector-potential terms.
737 do idim = 1, dim
738 !$omp parallel do
739 do ip = 1, np
740 psi(ip, idim) = this%phase(ip, ik)*psi(ip, idim)
741 end do
742 !$omp end parallel do
743 end do
744 end if
745
746 call profiling_out("PHASE_APPLY_SINGLE")
747
748 pop_sub(phase_apply_mf)
749 end subroutine phase_apply_mf
750
751
752 ! ---------------------------------------------------------------------------------------
754 !
755 subroutine phase_phase_spiral(this, der, psib)
756 class(phase_t), intent(in) :: this
757 type(derivatives_t), intent(in) :: der
758 class(wfs_elec_t), intent(inout) :: psib
759
760 integer :: ip, ii, sp
761 integer, allocatable :: spin_label(:)
762 type(accel_mem_t) :: spin_label_buffer
763 integer(int64) :: bsize
764 integer(int64), dimension(2) :: np, gsizes, bsizes
765
766 push_sub(phase_phase_spiral)
767 call profiling_in("PBC_PHASE_SPIRAL")
768
769 call profiling_count_operations(6*(der%mesh%np_part-der%mesh%np)*psib%nst_linear)
770
771 assert(der%boundaries%spiral)
772 assert(psib%type() == type_cmplx)
773
774 sp = der%mesh%np
775 if (der%mesh%parallel_in_domains) sp = der%mesh%np + der%mesh%pv%np_ghost
776
777
778 select case (psib%status())
779 case (batch_packed)
780
781 !$omp parallel do private(ip, ii)
782 do ip = sp + 1, der%mesh%np_part
783 do ii = 1, psib%nst_linear, 2
784 if (this%spin(3,psib%linear_to_ist(ii), psib%ik)>0) then
785 psib%zff_pack(ii+1, ip) = psib%zff_pack(ii+1, ip)*this%phase_spiral(ip-sp, 1)
786 else
787 psib%zff_pack(ii, ip) = psib%zff_pack(ii, ip)*this%phase_spiral(ip-sp, 2)
788 end if
789 end do
790 end do
791 !$omp end parallel do
792
793 case (batch_not_packed)
794
795 !$omp parallel private(ii, ip)
796 do ii = 1, psib%nst_linear, 2
797 if (this%spin(3,psib%linear_to_ist(ii), psib%ik)>0) then
798 !$omp do
799 do ip = sp + 1, der%mesh%np_part
800 psib%zff_linear(ip, ii+1) = psib%zff_linear(ip, ii+1)*this%phase_spiral(ip-sp, 1)
801 end do
802 !$omp end do nowait
803 else
804 !$omp do
805 do ip = sp + 1, der%mesh%np_part
806 psib%zff_linear(ip, ii) = psib%zff_linear(ip, ii)*this%phase_spiral(ip-sp, 2)
807 end do
808 !$omp end do nowait
809 end if
810 end do
811 !$omp end parallel
812
814
815 assert(accel_is_enabled())
816
817 ! generate array of offsets for access of psib and phase_spiral:
818 ! TODO: Move this to the routine where spin(:,:,:) is generated
819 ! and also move the buffer to the GPU at this point to
820 ! avoid unecessary latency here!
821
822 safe_allocate(spin_label(1:psib%nst_linear))
823 spin_label = 0
824 do ii = 1, psib%nst_linear, 2
825 if (this%spin(3, psib%linear_to_ist(ii), psib%ik) > 0) spin_label(ii)=1
826 end do
827
828 call accel_create_buffer(spin_label_buffer, accel_mem_read_only, type_integer, psib%nst_linear)
829 call accel_write_buffer(spin_label_buffer, psib%nst_linear, spin_label)
830
831 call accel_kernel_start_call(kernel_phase_spiral, 'phase_spiral.cu', 'phase_spiral_apply<double>')
832
835 call accel_set_kernel_arg(kernel_phase_spiral, 2, der%mesh%np_part)
836 call accel_set_kernel_arg(kernel_phase_spiral, 3, psib%ff_device)
837 call accel_set_kernel_arg(kernel_phase_spiral, 4, log2(psib%pack_size(1)))
838 call accel_set_kernel_arg(kernel_phase_spiral, 5, this%buff_phase_spiral)
839 call accel_set_kernel_arg(kernel_phase_spiral, 6, spin_label_buffer)
840
841 ! Compute the grid size
842 bsize = accel_kernel_block_size(kernel_phase_spiral)/psib%pack_size(1)
843 np = (/psib%pack_size(1)/2_int64, int(der%mesh%np_part - sp, int64)/)
844 bsizes = (/psib%pack_size(1)/2, 2*bsize/)
845 call accel_grid_size(np, bsizes, gsizes)
846
847 call accel_kernel_run(kernel_phase_spiral, bsizes, gsizes)
848
849 call accel_finish()
851 call accel_free_buffer(spin_label_buffer)
852
853 safe_deallocate_a(spin_label)
854
855 end select
856
857 call profiling_out("PBC_PHASE_SPIRAL")
858 pop_sub(phase_phase_spiral)
859 end subroutine phase_phase_spiral
860
861
862 ! ---------------------------------------------------------------------------------------
863 logical pure function phase_is_allocated(this)
864 class(phase_t), intent(in) :: this
865
866 phase_is_allocated = allocated(this%phase)
867 end function phase_is_allocated
868
869 !----------------------------------------------------------
876 subroutine phase_copy_and_set_phase(phase, gr, kpt, psib, psib_with_phase)
877 class(phase_t), intent(in) :: phase
878 type(grid_t), intent(in) :: gr
879 type(distributed_t), intent(in) :: kpt
880 type(wfs_elec_t), intent(in) :: psib
881 type(wfs_elec_t), intent(out) :: psib_with_phase
882
883 integer :: k_offset, n_boundary_points
884
886
887 call psib%copy_to(psib_with_phase)
888 if (phase%is_allocated()) then
889 call phase%apply_to(gr, gr%np, conjugate = .false., psib = psib_with_phase, src = psib, async=.true.)
890 ! apply phase correction while setting boundary -> memory needs to be
891 ! accessed only once
892 k_offset = psib%ik - kpt%start
893 n_boundary_points = int(gr%np_part - gr%np)
894 call boundaries_set(gr%der%boundaries, gr, psib_with_phase, phase_correction = phase%phase_corr(:, psib%ik), &
895 buff_phase_corr = phase%buff_phase_corr, offset=k_offset*n_boundary_points, async=.true.)
896 else
897 call psib%copy_data_to(gr%np, psib_with_phase)
898 call boundaries_set(gr%der%boundaries, gr, psib_with_phase)
899 end if
900
901 call psib_with_phase%do_pack(copy = .true.)
902
904 end subroutine phase_copy_and_set_phase
905
906
907end module phase_oct_m
908
909!! Local Variables:
910!! mode: f90
911!! coding: utf-8
912!! End:
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
integer function, public accel_kernel_block_size(kernel)
Definition: accel.F90:1149
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:941
subroutine, public accel_kernel_start_call(this, file_name, kernel_name, flags)
Definition: accel.F90:1716
subroutine, public accel_finish()
Definition: accel.F90:1059
subroutine, public accel_detach_buffer(this)
Clear a buffer handle without freeing device memory.
Definition: accel.F90:1010
integer, parameter, public accel_mem_read_write
Definition: accel.F90:185
type(accel_kernel_t), target, save, public kernel_phase_spiral
Definition: accel.F90:269
pure logical function, public accel_is_enabled()
Definition: accel.F90:372
integer, parameter, public accel_mem_read_only
Definition: accel.F90:185
This module implements batches of mesh functions.
Definition: batch.F90:135
integer, parameter, public batch_not_packed
functions are stored in CPU memory, unpacked order
Definition: batch.F90:287
integer, parameter, public batch_device_packed
functions are stored in device memory in packed order
Definition: batch.F90:287
integer, parameter, public batch_packed
functions are stored in CPU memory, in transposed (packed) order
Definition: batch.F90:287
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:118
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:124
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
real(real64), parameter, public m_zero
Definition: global.F90:200
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements the underlying real-space grid.
Definition: grid.F90:119
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
integer(int64) function, public mesh_periodic_point(mesh, space, ip)
This function returns the point inside the grid corresponding to a boundary point when PBCs are used....
Definition: mesh.F90:725
real(real64) function, dimension(1:mesh%box%dim), public mesh_x_global(mesh, ipg)
Given a global point index, this function returns the coordinates of the point.
Definition: mesh.F90:818
subroutine phase_phase_spiral(this, der, psib)
apply spiral phase
Definition: phase.F90:851
subroutine phase_unset_phase_corr(phase, mesh, psib, async)
unset the phase correction (if necessary)
Definition: phase.F90:612
subroutine, public phase_accel_rebuild(phase, mesh, kpt)
Rebuild phase accelerator buffers after an intrinsic copy.
Definition: phase.F90:538
subroutine phase_copy_and_set_phase(phase, gr, kpt, psib, psib_with_phase)
Copy a batch to another batch and apply the Bloch phase to it.
Definition: phase.F90:972
subroutine phase_init_phases(phase, gr, kpt, kpoints, d, space)
Initiliaze the phase arrays and copy to GPU the data.
Definition: phase.F90:228
subroutine phase_end(phase)
Releases the memory of the phase object.
Definition: phase.F90:511
subroutine phase_update_phases(phase, mesh, kpt, kpoints, d, space, uniform_vector_potential)
Update the phases.
Definition: phase.F90:339
logical pure function phase_is_allocated(this)
Definition: phase.F90:959
subroutine phase_apply_batch(this, mesh, np, conjugate, psib, src, async)
apply (remove) the phase to the wave functions before (after) applying the Hamiltonian
Definition: phase.F90:637
subroutine phase_set_phase_corr(phase, mesh, psib, async)
set the phase correction (if necessary)
Definition: phase.F90:586
subroutine phase_apply_mf(this, psi, np, dim, ik, conjugate)
apply (or remove) the phase to a wave function psi
Definition: phase.F90:805
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:631
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:554
This module handles spin dimensions of the states and the k-point distribution.
type(type_t), parameter, public type_cmplx
Definition: types.F90:136
type(type_t), parameter, public type_integer
Definition: types.F90:137
type(type_t), parameter, public type_float
Definition: types.F90:135
class representing derivatives
Distribution of N instances over mpi_grpsize processes, for the local rank mpi_grprank....
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:171
Describes mesh distribution to nodes.
Definition: mesh.F90:187
A container for the phase.
Definition: phase.F90:180
class for organizing spins and k-points
batches of electronic states
Definition: wfs_elec.F90:141
int true(void)