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