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