30 use,
intrinsic :: iso_fortran_env
57 logical :: parallel_in_domains
58 type(mpi_grp_t) :: mpi_grp
60 integer :: rs_n_global(1:3)
61 integer :: fs_n_global(1:3)
64 integer :: rs_istart(1:3)
65 integer :: fs_istart(1:3)
66 integer :: center(1:3)
68 integer,
allocatable :: fs_ifx(:)
69 integer,
allocatable :: fs_ify(:)
70 integer,
allocatable :: fs_ifz(:)
72 real(real64),
allocatable :: Lrs(:,:)
73 real(real64),
allocatable :: Lfs(:,:)
75 integer,
allocatable :: np_local(:)
76 integer,
allocatable :: xlocal(:)
77 integer,
allocatable :: local(:,:)
78 integer,
allocatable :: np_local_fs(:)
79 integer,
allocatable :: xlocal_fs(:)
80 integer,
allocatable :: local_fs(:,:)
83 type(fft_t),
allocatable :: fft
84 logical,
private :: has_cube_mapping = .false.
87 real(real64) :: spacing(3)
89 type(lattice_vectors_t),
allocatable :: latt
91 type(mesh_cube_map_t) :: cube_map
92 logical :: cube_map_present = .false.
93 integer :: batch_capacity
104 integer :: start_xyz(1:3)
105 integer :: end_xyz(1:3)
111 subroutine cube_init(cube, nn, namespace, space, spacing, coord_system, fft_type, fft_library, dont_optimize, nn_out, &
112 mpi_grp, need_partition, tp_enlarge, blocksize, batch_size, nthreads, single)
113 type(cube_t),
intent(out) :: cube
114 integer,
contiguous,
intent(in) :: nn(:)
115 type(namespace_t),
intent(in) :: namespace
116 class(space_t),
intent(in) :: space
117 real(real64),
contiguous,
intent(in) :: spacing(:)
118 class(coordinate_system_t),
intent(in) :: coord_system
119 integer,
optional,
intent(in) :: fft_type
120 integer,
optional,
intent(in) :: fft_library
121 logical,
optional,
intent(in) :: dont_optimize
122 integer,
optional,
intent(out) :: nn_out(3)
124 type(mpi_grp_t),
optional,
intent(in) :: mpi_grp
125 logical,
optional,
intent(in) :: need_partition
126 real(real64),
optional,
intent(in) :: tp_enlarge(3)
129 integer,
optional,
intent(in) :: blocksize
131 integer,
optional,
intent(in) :: batch_size
133 integer,
optional,
intent(in) :: nthreads
134 logical,
optional,
intent(in) :: single
136 type(MPI_Comm) :: comm
137 integer :: tmp_n(3), fft_type_, optimize_parity(3), fft_library_, nn3d(3)
138 integer :: effdim_fft, my_n(3), idir, idir2
139 logical :: optimize(3)
140 type(mpi_grp_t) :: mpi_grp_
141 real(real64) :: tp_enlarge_(3), lattice_vectors(3, 3)
142 type(space_t) :: cube_space
147 assert(space%dim <= 3)
149 nn3d(1:space%dim) = nn(1:space%dim)
150 nn3d(space%dim+1:3) = 1
152 cube%spacing(1:space%dim) = spacing(1:space%dim)
153 cube%spacing(space%dim+1:3) = -
m_one
158 if (
present(tp_enlarge)) tp_enlarge_(:)=tp_enlarge(:)
160 effdim_fft = min(3, space%dim)
163 if (
present(mpi_grp)) mpi_grp_ = mpi_grp
167 if (
present(fft_library))
then
168 fft_library_ = fft_library
175 write(
message(1),
'(a)')
'You have selected the PFFT for FFT, but it was not linked.'
188 cube%batch_capacity = 1
193 if (
present(blocksize))
then
194 assert(
present(need_partition).and.need_partition)
201 cube%rs_n_global = nn3d
202 cube%fs_n_global = nn3d
203 cube%fs_n = cube%fs_n_global
207 cube%parallel_in_domains = (mpi_grp_%size > 1)
208 call cube_set_blocksize(cube%rs_n_global, blocksize, mpi_grp_%rank, cube%rs_n, cube%rs_istart)
210 cube%rs_n_global = nn3d
211 cube%fs_n_global = nn3d
212 cube%rs_n = cube%rs_n_global
213 cube%fs_n = cube%fs_n_global
217 if (
present(nn_out)) nn_out(1:3) = nn3d(1:3)
219 safe_allocate(cube%fft)
222 optimize(1:3) = .false.
223 optimize_parity(1:3) = 0
224 optimize(space%periodic_dim + 1:effdim_fft) = .
true.
225 optimize_parity(space%periodic_dim + 1:effdim_fft) = 1
227 if (
present(dont_optimize))
then
228 if (dont_optimize) optimize = .false.
233 call fft_init(cube%fft, tmp_n, space%dim, fft_type_, fft_library_, optimize, optimize_parity, &
234 comm=comm, mpi_grp = mpi_grp_, use_aligned=.
true., howmany=cube%batch_capacity, &
236 if (
present(nn_out)) nn_out(1:3) = tmp_n(1:3)
238 call fft_get_dims(cube%fft, cube%rs_n_global, cube%fs_n_global, cube%rs_n, cube%fs_n, &
239 cube%rs_istart, cube%fs_istart)
247 call fft_init_stage1(cube%fft, namespace, cube%Lrs, cube%rs_n_global, &
248 dft_nodes = .not.
present(tp_enlarge))
250 call fft_get_dims(cube%fft, cube%rs_n_global, cube%fs_n_global, cube%rs_n, cube%fs_n, &
251 cube%rs_istart, cube%fs_istart)
256 if (.not.
allocated(cube%Lrs))
then
260 cube%center(1:3) = cube%rs_n_global(1:3)/2 + 1
267 if (
present(need_partition) .and. cube%parallel_in_domains)
then
268 cube%has_cube_mapping = need_partition
270 cube%has_cube_mapping = .false.
272 if (cube%has_cube_mapping)
then
278 select type (coord_system)
284 my_n(1:space%periodic_dim) = cube%rs_n_global(1:space%periodic_dim) + 1
285 my_n(space%periodic_dim + 1:space%dim) = cube%rs_n_global(space%periodic_dim + 1:space%dim)
288 do idir = 1, space%dim
289 do idir2 = 1, space%dim
290 lattice_vectors(idir2, idir) = cube%spacing(idir) * (my_n(idir) - 1) * coord_system%basis%vectors(idir2, idir)
293 do idir = space%dim + 1, 3
294 lattice_vectors(idir, idir) =
m_one
298 cube_space%periodic_dim = space%periodic_dim
299 safe_allocate(cube%latt)
302 message(1) =
"The cube only support affine coordinate systems."
311 type(
cube_t),
intent(inout) :: cube
315 if (
allocated(cube%fft))
then
317 safe_deallocate_a(cube%fft)
320 if (cube%has_cube_mapping)
then
321 safe_deallocate_a(cube%np_local)
322 safe_deallocate_a(cube%xlocal)
323 safe_deallocate_a(cube%local)
325 safe_deallocate_a(cube%np_local_fs)
326 safe_deallocate_a(cube%xlocal_fs)
327 safe_deallocate_a(cube%local_fs)
330 if (cube%cube_map_present)
then
334 safe_deallocate_a(cube%Lrs)
335 safe_deallocate_a(cube%Lfs)
337 safe_deallocate_a(cube%latt)
338 safe_deallocate_a(cube%fs_ifx)
339 safe_deallocate_a(cube%fs_ify)
340 safe_deallocate_a(cube%fs_ifz)
347 class(
cube_t),
intent(in) :: cube
349 l = cube%rs_n_global(1:3) * cube%spacing(1:3)
365 class(
cube_t),
intent(inout) :: cube
367 integer :: lx, ly, lz
371 safe_allocate(cube%fs_ifx(1:max(1, cube%fs_n(1))))
372 safe_allocate(cube%fs_ify(1:max(1, cube%fs_n(2))))
373 safe_allocate(cube%fs_ifz(1:max(1, cube%fs_n(3))))
375 do lx = 1, cube%fs_n(1)
376 cube%fs_ifx(lx) =
pad_feq(cube%fs_istart(1) + lx - 1, cube%rs_n_global(1), .
true.)
378 do ly = 1, cube%fs_n(2)
379 cube%fs_ify(ly) =
pad_feq(cube%fs_istart(2) + ly - 1, cube%rs_n_global(2), .
true.)
381 do lz = 1, cube%fs_n(3)
382 cube%fs_ifz(lz) =
pad_feq(cube%fs_istart(3) + lz - 1, cube%rs_n_global(3), .
true.)
392 type(
cube_t),
intent(inout) :: cube
393 integer,
intent(in) :: fft_library
396 select case (fft_library)
398 cube%fft%pnfft%set_defaults = .
true.
400 cube%fft%pnfft%sigma = 1.1_real64
412 type(
cube_t),
intent(inout) :: cube
413 real(real64),
intent(in) :: tp_enlarge(3)
414 real(real64),
intent(in) :: spacing(3)
415 integer,
intent(in) :: fft_library
418 integer :: ii, nn(3), maxn, idim
423 nn(1:3) = cube%fs_n_global(1:3)
426 safe_allocate(cube%Lrs(1:maxn, 1:3))
431 if (tp_enlarge(idim) >
m_one)
then
432 do ii = 2, nn(idim) - 1
433 cube%Lrs(ii, idim) = (ii - int(nn(idim)/2) -1) * spacing(idim)
435 cube%Lrs(1, idim) = (-int(nn(idim)/2)) * spacing(idim) * tp_enlarge(idim)
436 cube%Lrs(nn(idim), idim) = (int(nn(idim)/2)) * spacing(idim) * tp_enlarge(idim)
439 cube%Lrs(ii, idim) = (ii - int(nn(idim)/2) -1) * spacing(idim)
448 safe_allocate(cube%Lfs(1:maxn, 1:3))
452 temp =
m_two *
m_pi / (nn(idim) * spacing(idim))
460 cube%Lfs(ii, idim) = (ii - nn(idim)/2 - 1)*temp/tp_enlarge(idim)
462 cube%Lfs(ii, idim) =
pad_feq(ii,nn(idim), .
true.) * temp
476 type(
cube_t),
intent(in) :: cube
477 integer,
intent(in) :: ixyz(3)
478 integer,
intent(out) :: lxyz(3)
480 lxyz(1) = ixyz(1) - cube%rs_istart(1) + 1
481 lxyz(2) = ixyz(2) - cube%rs_istart(2) + 1
482 lxyz(3) = ixyz(3) - cube%rs_istart(3) + 1
483 is_here = lxyz(1) >= 1 .and. lxyz(1) <= cube%rs_n(1) .and. &
484 lxyz(2) >= 1 .and. lxyz(2) <= cube%rs_n(2) .and. &
485 lxyz(3) >= 1 .and. lxyz(3) <= cube%rs_n(3)
496 type(
cube_t),
intent(in) :: cube
498 if (
allocated(cube%fft))
then
499 fft_library = cube%fft%library
508 type(
cube_t),
intent(inout) :: cube
509 logical,
intent(in) :: fs
511 integer :: tmp_local(6), position, process, ix, iy, iz, index
512 integer,
allocatable :: local_sizes(:)
513 integer(int64) :: number_points
519 tmp_local(1) = cube%rs_istart(1)
520 tmp_local(2) = cube%rs_istart(2)
521 tmp_local(3) = cube%rs_istart(3)
522 tmp_local(4) = cube%rs_n(1)
523 tmp_local(5) = cube%rs_n(2)
524 tmp_local(6) = cube%rs_n(3)
526 if (cube%parallel_in_domains)
then
527 safe_allocate(local_sizes(1:6*cube%mpi_grp%size))
529 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
532 safe_allocate(local_sizes(1:6))
533 local_sizes = tmp_local
538 safe_allocate(cube%xlocal(1:cube%mpi_grp%size))
539 safe_allocate(cube%np_local(1:cube%mpi_grp%size))
541 number_points = cube%rs_n_global(1) * cube%rs_n_global(2)
542 number_points = number_points * cube%rs_n_global(3)
543 if (number_points >= huge(0))
then
544 message(1) =
"Error: too many points for the normal cube. Please try to use a distributed FFT."
547 safe_allocate(cube%local(1:cube%rs_n_global(1)*cube%rs_n_global(2)*cube%rs_n_global(3), 1:3))
550 do process = 1, cube%mpi_grp%size
551 position = ((process-1)*6)+1
552 if (position == 1)
then
554 cube%np_local(1) = local_sizes(4)*local_sizes(5)*local_sizes(6)
557 cube%xlocal(process) = cube%xlocal(process-1) + cube%np_local(process-1)
558 cube%np_local(process) = local_sizes(position+3)*local_sizes(position+4)*local_sizes(position+5)
563 do iz = local_sizes(position+2), local_sizes(position+2)+local_sizes(position+5)-1
564 do iy = local_sizes(position+1), local_sizes(position+1)+local_sizes(position+4)-1
565 do ix = local_sizes(position), local_sizes(position)+local_sizes(position+3)-1
566 cube%local(index, 1) = ix
567 cube%local(index, 2) = iy
568 cube%local(index, 3) = iz
579 tmp_local(1) = cube%fs_istart(1)
580 tmp_local(2) = cube%fs_istart(2)
581 tmp_local(3) = cube%fs_istart(3)
582 tmp_local(4) = cube%fs_n(1)
583 tmp_local(5) = cube%fs_n(2)
584 tmp_local(6) = cube%fs_n(3)
587 if (cube%parallel_in_domains)
then
589 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
592 local_sizes = tmp_local
597 safe_allocate(cube%xlocal_fs(1:cube%mpi_grp%size))
598 safe_allocate(cube%np_local_fs(1:cube%mpi_grp%size))
600 number_points = cube%fs_n_global(1) * cube%fs_n_global(2)
601 number_points = number_points * cube%fs_n_global(3)
602 if (number_points >= huge(0))
then
603 message(1) =
"Error: too many points for the normal cube. Please try to use a distributed FFT."
606 safe_allocate(cube%local_fs(1:cube%fs_n_global(1)*cube%fs_n_global(2)*cube%fs_n_global(3), 1:3))
609 do process = 1, cube%mpi_grp%size
610 position = ((process-1)*6)+1
611 if (position == 1)
then
612 cube%xlocal_fs(1) = 1
613 cube%np_local_fs(1) = local_sizes(4)*local_sizes(5)*local_sizes(6)
616 cube%xlocal_fs(process) = cube%xlocal_fs(process-1) + cube%np_local_fs(process-1)
617 cube%np_local_fs(process) = local_sizes(position+3)*local_sizes(position+4)*local_sizes(position+5)
622 do iz = local_sizes(position+2), local_sizes(position+2)+local_sizes(position+5)-1
623 do iy = local_sizes(position+1), local_sizes(position+1)+local_sizes(position+4)-1
624 do ix = local_sizes(position), local_sizes(position)+local_sizes(position+3)-1
625 cube%local_fs(index, 1) = ix
626 cube%local_fs(index, 2) = iy
627 cube%local_fs(index, 3) = iz
640 safe_deallocate_a(local_sizes)
648 integer pure function cube_point_to_process(mpi_grp, xyz, part) result(process)
650 integer,
intent(in) :: xyz(1:3)
659 do proc = 1, mpi_grp%size
661 if (all(xyz >= part(proc)%start_xyz) .and. all(xyz <= part(proc)%end_xyz))
then
669 if (.not. found)
then
679 integer,
intent(in) :: rs_n_global(1:3)
680 integer,
intent(in) :: blocksize
681 integer,
intent(in) :: rank
682 integer,
intent(out) :: rs_n(1:3)
683 integer,
intent(out) :: rs_istart(1:3)
685 integer :: imin, imax
690 imin = min(blocksize * rank, rs_n_global(3))
691 imax = min(imin + blocksize, rs_n_global(3))
692 rs_istart(3) = 1 + imin
693 rs_n(3) = imax - imin
698 type(
cube_t),
intent(in) :: cube
701 integer :: tmp_local(6), position, process
702 integer,
allocatable :: local_sizes(:)
707 tmp_local(1) = cube%rs_istart(1)
708 tmp_local(2) = cube%rs_istart(2)
709 tmp_local(3) = cube%rs_istart(3)
710 tmp_local(4) = cube%rs_n(1)
711 tmp_local(5) = cube%rs_n(2)
712 tmp_local(6) = cube%rs_n(3)
714 if (cube%parallel_in_domains)
then
715 safe_allocate(local_sizes(1:6*cube%mpi_grp%size))
716 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
718 safe_allocate(local_sizes(1:6))
719 local_sizes(:) = tmp_local(:)
722 do process = 1, cube%mpi_grp%size
723 position = ((process-1)*6)+1
725 part(process)%start_xyz(1) = local_sizes(position)
726 part(process)%start_xyz(2) = local_sizes(position+1)
727 part(process)%start_xyz(3) = local_sizes(position+2)
728 part(process)%end_xyz(1) = local_sizes(position)+local_sizes(position+3)-1
729 part(process)%end_xyz(2) = local_sizes(position+1)+local_sizes(position+4)-1
730 part(process)%end_xyz(3) = local_sizes(position+2)+local_sizes(position+5)-1
739 type(
cube_t),
intent(in) :: cube
740 type(namespace_t),
intent(in) :: namespace
742 integer :: nn, ii, jj, kk
746 character(len=3) :: filenum
752 safe_allocate(part(1:cube%mpi_grp%size))
755 if (mpi_world%is_root())
then
756 call io_mkdir(
'debug/cube_partition', namespace)
757 npart = cube%mpi_grp%size
762 write(filenum,
'(i3.3)') nn
764 iunit = io_open(
'debug/cube_partition/cube_partition.'//filenum, &
765 namespace, action=
'write')
766 do kk = 1, cube%rs_n_global(3)
767 do jj = 1, cube%rs_n_global(2)
768 do ii = 1, cube%rs_n_global(1)
773 write(iunit,
'(3i8)') ii, jj, kk
784 safe_deallocate_a(part)
787 call cube%mpi_grp%barrier()
794 type(
cube_t),
intent(inout) :: cube
795 class(mesh_t),
intent(in) :: mesh
799 call mesh_cube_map_init(cube%cube_map, mesh, mesh%np)
800 cube%cube_map_present = .
true.
subroutine cube_set_blocksize(rs_n_global, blocksize, rank, rs_n, rs_istart)
subroutine cube_init_fourier_mode_numbers_mapping(cube)
Initialises the mapping between local cube index in Fourier space and global FFT integer frequencies....
subroutine cube_do_mapping(cube, fs)
do the mapping between global and local points of the cube
subroutine, public cube_end(cube)
pure real(real64) function, dimension(3) cube_length(cube)
Total length of the cube in each dimension.
logical function, public cube_global2local(cube, ixyz, lxyz)
True if global coordinates belong to this process. On output lxyz contains the local coordinates.
subroutine, public cube_init(cube, nn, namespace, space, spacing, coord_system, fft_type, fft_library, dont_optimize, nn_out, mpi_grp, need_partition, tp_enlarge, blocksize, batch_size, nthreads, single)
subroutine cube_tp_fft_defaults(cube, fft_library)
integer pure function, public cube_point_to_process(mpi_grp, xyz, part)
integer function, public cube_getfftlibrary(cube)
Returns the FFT library of the cube. Possible values are FFTLIB_NONE, FFTLIB_FFTW,...
subroutine cube_init_coords(cube, tp_enlarge, spacing, fft_library)
subroutine, public cube_partition(cube, part)
subroutine, public cube_init_cube_map(cube, mesh)
subroutine cube_partition_messages_debug(cube, namespace)
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
subroutine, public fft_init_stage1(this, namespace, XX, nn, dft_nodes)
Some fft-libraries (only NFFT for the moment) need an additional precomputation stage that depends on...
integer, parameter, public fft_none
global constants
subroutine, public fft_end(this)
subroutine, public fft_init(this, nn, dim, type, library, optimize, optimize_parity, comm, mpi_grp, use_aligned, howmany, nthreads, single)
integer, public fft_default_lib
pure integer function, public pad_feq(ii, nn, mode)
convert between array index and G-vector
integer, parameter, public fftlib_accel
subroutine, public fft_get_dims(fft, rs_n_global, fs_n_global, rs_n, fs_n, rs_istart, fs_istart)
integer, parameter, public fftlib_nfft
integer, parameter, public fftlib_none
integer, parameter, public fftlib_pnfft
integer, parameter, public fftlib_pfft
integer, parameter, public fftlib_fftw
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public m_pi
some mathematical constants
real(real64), parameter, public m_one
subroutine, public mesh_cube_map_end(this)
This module defines the meshes, which are used in Octopus.
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
type(mpi_comm), parameter, public mpi_comm_undefined
used to indicate a communicator has not been initialized
type(mpi_grp_t), public mpi_world
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
The low level module to work with the PFFT library. http:
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
It is intended to be used within a vector.
This is defined even when running serial.