Octopus
cube.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2011 M. Marques, A. Castro, A. Rubio,
2!! G. Bertsch, M. Oliveira, J. Alberdi-Rodriguez
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 cube_oct_m
23 use accel_oct_m
26 use debug_oct_m
27 use fft_oct_m
28 use global_oct_m
29 use io_oct_m
30 use, intrinsic :: iso_fortran_env
33 use mesh_oct_m
35 use mpi_oct_m
37 use parser_oct_m
38 use pfft_oct_m
40 use space_oct_m
41
42 implicit none
43 private
44 public :: &
45 cube_t, &
47 cube_init, &
54
55 type cube_t
56 ! Components are public by default
57 logical :: parallel_in_domains
58 type(mpi_grp_t) :: mpi_grp
59
60 integer :: rs_n_global(1:3)
61 integer :: fs_n_global(1:3)
62 integer :: rs_n(1:3)
63 integer :: fs_n(1:3)
64 integer :: rs_istart(1:3)
65 integer :: fs_istart(1:3)
66 integer :: center(1:3)
67
68 integer, allocatable :: fs_ifx(:)
69 integer, allocatable :: fs_ify(:)
70 integer, allocatable :: fs_ifz(:)
71
72 real(real64), allocatable :: Lrs(:,:)
73 real(real64), allocatable :: Lfs(:,:)
74
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(:,:)
81
82
83 type(fft_t), allocatable :: fft
84 logical, private :: has_cube_mapping = .false.
86
87 real(real64) :: spacing(3)
88 ! latt is declared as allocatable as a work-around for a bug in gfortran when invoking the finalizer of latt.
89 type(lattice_vectors_t), allocatable :: latt
90
91 type(mesh_cube_map_t) :: cube_map
92 logical :: cube_map_present = .false.
93 integer :: batch_capacity
94 contains
95 procedure :: length => cube_length
96 end type cube_t
97
103 type dimensions_t
104 integer :: start_xyz(1:3)
105 integer :: end_xyz(1:3)
106 end type dimensions_t
107
108contains
109
110 ! ---------------------------------------------------------
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
132 ! the batch size for the FFTW and cuFFT solvers
133 integer, optional, intent(in) :: nthreads
134 logical, optional, intent(in) :: single
135
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
143
144 push_sub(cube_init)
145
146 assert(all(nn > 0))
147 assert(space%dim <= 3)
148
149 nn3d(1:space%dim) = nn(1:space%dim)
150 nn3d(space%dim+1:3) = 1
151
152 cube%spacing(1:space%dim) = spacing(1:space%dim)
153 cube%spacing(space%dim+1:3) = -m_one
154 cube%batch_capacity = optional_default(batch_size, 1)
156 fft_type_ = optional_default(fft_type, fft_none)
157 tp_enlarge_(:) = (/m_one, m_one, m_one/)
158 if (present(tp_enlarge)) tp_enlarge_(:)=tp_enlarge(:)
160 effdim_fft = min(3, space%dim)
162 mpi_grp_ = mpi_world
163 if (present(mpi_grp)) mpi_grp_ = mpi_grp
165 if (fft_type_ /= fft_none) then
166
167 if (present(fft_library)) then
168 fft_library_ = fft_library
169 else
170 fft_library_ = fft_default_lib
171 end if
173#ifndef HAVE_PFFT
174 if (fft_library_ == fftlib_pfft) then
175 write(message(1),'(a)')'You have selected the PFFT for FFT, but it was not linked.'
176 call messages_fatal(1, namespace=namespace)
177 end if
178#endif
180 else
181 fft_library_ = fftlib_none
182 end if
183
184 ! Only FFTW and cuFFT can batch the FFT (howmany > 1); PFFT/NFFT/PNFFT run one transform at a
185 ! time, so a batched cube on those backends is not possible. Callers that requested a batch
186 ! (batch_size > 1) fall back to a per-function loop (see X(poisson_solve_batch)).
187 if (fft_library_ /= fftlib_fftw .and. fft_library_ /= fftlib_accel) then
188 cube%batch_capacity = 1
189 end if
191 ! Note: later we set parallel_in_domains if blocksize is given, too
192 cube%parallel_in_domains = (fft_library_ == fftlib_pfft .or. fft_library_ == fftlib_pnfft)
193 if (present(blocksize)) then
194 assert(present(need_partition).and.need_partition)
195 assert(fft_library_ == fftlib_none)
196 ! For all the different FFT libraries there are strange (?)
197 ! rules about how the decomposition is chosen. What we want
198 ! (for libvdwxc) is a cube parallelized according to the simple
199 ! but contrary rule "just do what I say". Hence the blocksize
200 ! parameter. (Later to be expanded to allow 2D distributions.)
201 cube%rs_n_global = nn3d
202 cube%fs_n_global = nn3d ! not to be used
203 cube%fs_n = cube%fs_n_global ! not to be used
204 cube%fs_istart = 1 ! not to be used
205
206 comm = mpi_grp_%comm
207 cube%parallel_in_domains = (mpi_grp_%size > 1) ! XXX whether comm size > 1
208 call cube_set_blocksize(cube%rs_n_global, blocksize, mpi_grp_%rank, cube%rs_n, cube%rs_istart)
209 else if (fft_library_ == fftlib_none) then
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
214 cube%rs_istart = 1
215 cube%fs_istart = 1
216 comm = mpi_comm_undefined
217 if (present(nn_out)) nn_out(1:3) = nn3d(1:3)
218 else
219 safe_allocate(cube%fft)
220 tmp_n = nn3d
221
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
226
227 if (present(dont_optimize)) then
228 if (dont_optimize) optimize = .false.
229 end if
230
231 if (present(tp_enlarge)) call cube_tp_fft_defaults(cube, fft_library_)
232
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, &
235 nthreads=nthreads, single=optional_default(single, .false.))
236 if (present(nn_out)) nn_out(1:3) = tmp_n(1:3)
237
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)
240
241 if (present(tp_enlarge) .or. fft_library_ == fftlib_nfft .or. fft_library_ == fftlib_pnfft) then
242 ! the (p)nfft nodes are the cube coordinates, so those are needed before stage1
243 call cube_init_coords(cube, tp_enlarge_, cube%spacing, fft_library_)
244 end if
245
246 if (fft_library_ == fftlib_nfft .or. fft_library_ == fftlib_pnfft) then
247 call fft_init_stage1(cube%fft, namespace, cube%Lrs, cube%rs_n_global, &
248 dft_nodes = .not. present(tp_enlarge))
249 !set local dimensions after stage1 - needed for PNFFT
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)
252 end if
253
254 end if
255
256 if (.not. allocated(cube%Lrs)) then
257 call cube_init_coords(cube, tp_enlarge_, cube%spacing, fft_library_)
258 end if
259
260 cube%center(1:3) = cube%rs_n_global(1:3)/2 + 1
261
263
264 call mpi_grp_init(cube%mpi_grp, comm)
265
266 ! Initialize mapping only if needed
267 if (present(need_partition) .and. cube%parallel_in_domains) then
268 cube%has_cube_mapping = need_partition
269 else
270 cube%has_cube_mapping = .false.
271 end if
272 if (cube%has_cube_mapping) then
273 call cube_do_mapping(cube, fs = fft_library_ == fftlib_pnfft)
274 end if
275
276 if (cube%parallel_in_domains) call cube_partition_messages_debug(cube, namespace)
277
278 select type (coord_system)
279 class is (affine_coordinates_t)
280 ! We are constructing a lattice vector for the cube
281 ! This differs from the actual lattice vectors if it is not an integer multiple of the spacing
282 ! mesh%idx%ll is "general" in aperiodic directions,
283 ! but "periodic" in periodic directions.
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)
286
287 lattice_vectors = m_zero
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)
291 end do
292 end do
293 do idir = space%dim + 1, 3
294 lattice_vectors(idir, idir) = m_one
295 end do
296
297 cube_space%dim = 3
298 cube_space%periodic_dim = space%periodic_dim
299 safe_allocate(cube%latt)
300 cube%latt = lattice_vectors_t(namespace, cube_space, lattice_vectors)
301 class default
302 message(1) = "The cube only support affine coordinate systems."
303 call messages_fatal(1, namespace=namespace)
304 end select
305
306 pop_sub(cube_init)
307 end subroutine cube_init
308
309 ! ---------------------------------------------------------
310 subroutine cube_end(cube)
311 type(cube_t), intent(inout) :: cube
312
313 push_sub(cube_end)
314
315 if (allocated(cube%fft)) then
316 call fft_end(cube%fft)
317 safe_deallocate_a(cube%fft)
318 end if
319
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)
324
325 safe_deallocate_a(cube%np_local_fs)
326 safe_deallocate_a(cube%xlocal_fs)
327 safe_deallocate_a(cube%local_fs)
328 end if
329
330 if (cube%cube_map_present) then
331 call mesh_cube_map_end(cube%cube_map)
332 end if
333
334 safe_deallocate_a(cube%Lrs)
335 safe_deallocate_a(cube%Lfs)
336
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)
341
342 pop_sub(cube_end)
343 end subroutine cube_end
344
346 pure function cube_length(cube) result(l)
347 class(cube_t), intent(in) :: cube
348 real(real64) :: l(3)
349 l = cube%rs_n_global(1:3) * cube%spacing(1:3)
350 end function cube_length
351
365 class(cube_t), intent(inout) :: cube
366
367 integer :: lx, ly, lz
368
370
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))))
374
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.)
377 end do
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.)
380 end do
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.)
383 end do
384
386
388
389
390 ! ---------------------------------------------------------
391 subroutine cube_tp_fft_defaults(cube, fft_library)
392 type(cube_t), intent(inout) :: cube
393 integer, intent(in) :: fft_library
394
395 push_sub(cube_tp_fft_defaults)
396 select case (fft_library)
397 case (fftlib_pnfft)
398 cube%fft%pnfft%set_defaults = .true.
399 cube%fft%pnfft%m = 2
400 cube%fft%pnfft%sigma = 1.1_real64
401
402 case default
403 !do nothing
404 end select
406 pop_sub(cube_tp_fft_defaults)
407 end subroutine cube_tp_fft_defaults
408
409
410 ! ---------------------------------------------------------
411 subroutine cube_init_coords(cube, tp_enlarge, spacing, fft_library)
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
416
417 real(real64) :: temp
418 integer :: ii, nn(3), maxn, idim
419
420 push_sub(cube_init_coords)
421
422
423 nn(1:3) = cube%fs_n_global(1:3)
424
425 maxn = maxval(nn)
426 safe_allocate(cube%Lrs(1:maxn, 1:3))
427 cube%Lrs(:,:) = m_zero
428
429 !! Real space coordinates
430 do idim = 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)
434 end do
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)
437 else
438 do ii = 1, nn(idim)
439 cube%Lrs(ii, idim) = (ii - int(nn(idim)/2) -1) * spacing(idim)
440 end do
441 end if
442 end do
443
444
445 !! Fourier space coordinates
446 if (fft_library /= fftlib_none) then
447
448 safe_allocate(cube%Lfs(1:maxn, 1:3))
449 cube%Lfs(:,:) = m_zero
450
451 do idim = 1,3
452 temp = m_two * m_pi / (nn(idim) * spacing(idim))
453!temp = M_PI / (nn * spacing(1))
454 do ii = 1, nn(idim)
455 if (fft_library == fftlib_nfft .or. fft_library == fftlib_pnfft) then
456 !The Fourier space is shrunk by the tp_enlarge factor
457 !cube%Lfs(ii, 1:3) = (ii - nn/2 - 1)*temp/tp_enlarge
458!HH NOTE:
459!not sure this is the right general factor
460 cube%Lfs(ii, idim) = (ii - nn(idim)/2 - 1)*temp/tp_enlarge(idim)
461 else
462 cube%Lfs(ii, idim) = pad_feq(ii,nn(idim), .true.) * temp
463 end if
464 end do
465 end do
466 end if
467
468 pop_sub(cube_init_coords)
469 end subroutine cube_init_coords
470
471
472 ! ---------------------------------------------------------
475 logical function cube_global2local(cube, ixyz, lxyz) result(is_here)
476 type(cube_t), intent(in) :: cube
477 integer, intent(in) :: ixyz(3)
478 integer, intent(out) :: lxyz(3)
479
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)
487 end function cube_global2local
488
489
490 ! ---------------------------------------------------------
495 integer function cube_getfftlibrary(cube) result(fft_library)
496 type(cube_t), intent(in) :: cube
497
498 if (allocated(cube%fft)) then
499 fft_library = cube%fft%library
500 else
501 fft_library = fftlib_none
502 end if
503 end function cube_getfftlibrary
504
505 ! ---------------------------------------------------------
507 subroutine cube_do_mapping(cube, fs)
508 type(cube_t), intent(inout) :: cube
509 logical, intent(in) :: fs
510
511 integer :: tmp_local(6), position, process, ix, iy, iz, index
512 integer, allocatable :: local_sizes(:)
513 integer(int64) :: number_points
514
515 push_sub(cube_do_mapping)
516
517 !!BEGIN:gather the local information into a unique vector.
518 !!do a gather in 3d of all the box, into a loop
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)
525
526 if (cube%parallel_in_domains) then
527 safe_allocate(local_sizes(1:6*cube%mpi_grp%size))
528 call profiling_in("CUBE_GAT")
529 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
530 call profiling_out("CUBE_GAT")
531 else
532 safe_allocate(local_sizes(1:6))
533 local_sizes = tmp_local
534 end if
535
536 call profiling_in("CUBE_MAP")
537
538 safe_allocate(cube%xlocal(1:cube%mpi_grp%size))
539 safe_allocate(cube%np_local(1:cube%mpi_grp%size))
540 ! make sure we do not run into integer overflow here
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."
545 call messages_fatal(1)
546 end if
547 safe_allocate(cube%local(1:cube%rs_n_global(1)*cube%rs_n_global(2)*cube%rs_n_global(3), 1:3))
548
549 index = 1
550 do process = 1, cube%mpi_grp%size
551 position = ((process-1)*6)+1
552 if (position == 1) then
553 cube%xlocal(1) = 1
554 cube%np_local(1) = local_sizes(4)*local_sizes(5)*local_sizes(6)
555 else
556 ! calculate the begin index and size of each process
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)
559 end if
560
561 ! save the mapping between the global x,y,z and the global index
562 ! and determine which partition the point belongs to
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
569 index = index + 1
570 end do
571 end do
572 end do
573 end do
574
575 call profiling_out("CUBE_MAP")
576
577 if (optional_default(fs,.false.)) then
578
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)
585
586 local_sizes = 0
587 if (cube%parallel_in_domains) then
588 call profiling_in("CUBE_GAT_FS")
589 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
590 call profiling_out("CUBE_GAT_FS")
591 else
592 local_sizes = tmp_local
593 end if
594
595 call profiling_in("CUBE_MAP_FS")
596
597 safe_allocate(cube%xlocal_fs(1:cube%mpi_grp%size))
598 safe_allocate(cube%np_local_fs(1:cube%mpi_grp%size))
599 ! make sure we do not run into integer overflow here
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."
604 call messages_fatal(1)
605 end if
606 safe_allocate(cube%local_fs(1:cube%fs_n_global(1)*cube%fs_n_global(2)*cube%fs_n_global(3), 1:3))
607
608 index = 1
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)
614 else
615 ! calculate the begin index and size of each process
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)
618 end if
619
620 ! save the mapping between the global x,y,z and the global index
621 ! and determine which partition the point belongs to
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
628 index = index + 1
629 end do
630 end do
631 end do
632 end do
633
634 call profiling_out("CUBE_MAP_FS")
635
636 end if
637
638
639
640 safe_deallocate_a(local_sizes)
641
642 pop_sub(cube_do_mapping)
643 end subroutine cube_do_mapping
644
645 !!> Given a x, y, z point of the cube, it returns the corresponding process
646 !!
647 !! last_found is used to speed-up the search
648 integer pure function cube_point_to_process(mpi_grp, xyz, part) result(process)
649 type(mpi_grp_t), intent(in) :: mpi_grp
650 integer, intent(in) :: xyz(1:3)
651 type(dimensions_t), contiguous, intent(in) :: part(:)
652
653 integer :: proc
654 logical :: found
655
656 ! No PUSH/POP because it is a PURE function
657
658 found = .false.
659 do proc = 1, mpi_grp%size
660 !Compare XYZ index
661 if (all(xyz >= part(proc)%start_xyz) .and. all(xyz <= part(proc)%end_xyz)) then
662 process = proc
663 found = .true.
664 exit
665 end if
666 end do
667
668 ! An error message should be raised, if this point is reached
669 if (.not. found) then
670 process = -1
671 end if
672
673 end function cube_point_to_process
674
675 ! Sets a 1D decomposition with fixed-size blocks over the last (least-contiguous) axis.
676 ! Each core will have <blocksize> slices except the last one which will typically have
677 ! less. (In some cases, there can be multiple trailing cores without any slices.)
678 subroutine cube_set_blocksize(rs_n_global, blocksize, rank, rs_n, rs_istart)
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)
684
685 integer :: imin, imax
686
687 rs_n = rs_n_global
688 rs_istart = 1
689
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
694 end subroutine cube_set_blocksize
695
696 ! ---------------------------------------------------------
697 subroutine cube_partition(cube, part)
698 type(cube_t), intent(in) :: cube
699 type(dimensions_t), intent(out) :: part(:)
700
701 integer :: tmp_local(6), position, process
702 integer, allocatable :: local_sizes(:)
703
704 push_sub(cube_partition)
705
706 !!gather the local information into a unique vector.
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)
713
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)
717 else
718 safe_allocate(local_sizes(1:6))
719 local_sizes(:) = tmp_local(:)
720 end if
721
722 do process = 1, cube%mpi_grp%size
723 position = ((process-1)*6)+1
724
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
731
732 end do
733
734 pop_sub(cube_partition)
735 end subroutine cube_partition
736
737 ! ---------------------------------------------------------
738 subroutine cube_partition_messages_debug(cube, namespace)
739 type(cube_t), intent(in) :: cube
740 type(namespace_t), intent(in) :: namespace
741
742 integer :: nn, ii, jj, kk ! Counters.
743 integer :: ixyz(3) ! Current value of xyz
744 integer :: npart
745 integer :: iunit ! For debug output to files.
746 character(len=3) :: filenum
747 type(dimensions_t), allocatable :: part(:)
748
750
751 if (debug%info) then
752 safe_allocate(part(1:cube%mpi_grp%size))
753 call cube_partition(cube, part)
754
755 if (mpi_world%is_root()) then
756 call io_mkdir('debug/cube_partition', namespace)
757 npart = cube%mpi_grp%size
758
759 ! Debug output. Write points of each partition in a different file.
760 do nn = 1, npart
761
762 write(filenum, '(i3.3)') nn
763
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)
769 ixyz(1) = ii
770 ixyz(2) = jj
771 ixyz(3) = kk
772 if (cube_point_to_process(cube%mpi_grp, ixyz, part) == nn) then
773 write(iunit, '(3i8)') ii, jj, kk
774 end if
775 end do
776 end do
777 end do
778 call io_close(iunit)
779 end do
780
781
782 end if
783
784 safe_deallocate_a(part)
785 end if
786
787 call cube%mpi_grp%barrier()
788
790 end subroutine cube_partition_messages_debug
791
792 ! ---------------------------------------------------------
793 subroutine cube_init_cube_map(cube, mesh)
794 type(cube_t), intent(inout) :: cube
795 class(mesh_t), intent(in) :: mesh
796
797 push_sub(cube_init_cube_map)
798
799 call mesh_cube_map_init(cube%cube_map, mesh, mesh%np)
800 cube%cube_map_present = .true.
801
802 pop_sub(cube_init_cube_map)
803 end subroutine cube_init_cube_map
804end module cube_oct_m
805
806
807!! Local Variables:
808!! mode: f90
809!! coding: utf-8
810!! End:
subroutine cube_set_blocksize(rs_n_global, blocksize, rank, rs_n, rs_istart)
Definition: cube.F90:774
subroutine cube_init_fourier_mode_numbers_mapping(cube)
Initialises the mapping between local cube index in Fourier space and global FFT integer frequencies....
Definition: cube.F90:460
subroutine cube_do_mapping(cube, fs)
do the mapping between global and local points of the cube
Definition: cube.F90:603
subroutine, public cube_end(cube)
Definition: cube.F90:406
pure real(real64) function, dimension(3) cube_length(cube)
Total length of the cube in each dimension.
Definition: cube.F90:442
logical function, public cube_global2local(cube, ixyz, lxyz)
True if global coordinates belong to this process. On output lxyz contains the local coordinates.
Definition: cube.F90:571
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)
Definition: cube.F90:208
subroutine cube_tp_fft_defaults(cube, fft_library)
Definition: cube.F90:487
integer pure function, public cube_point_to_process(mpi_grp, xyz, part)
Definition: cube.F90:744
integer function, public cube_getfftlibrary(cube)
Returns the FFT library of the cube. Possible values are FFTLIB_NONE, FFTLIB_FFTW,...
Definition: cube.F90:591
subroutine cube_init_coords(cube, tp_enlarge, spacing, fft_library)
Definition: cube.F90:507
subroutine, public cube_partition(cube, part)
Definition: cube.F90:793
subroutine, public cube_init_cube_map(cube, mesh)
Definition: cube.F90:889
subroutine cube_partition_messages_debug(cube, namespace)
Definition: cube.F90:834
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:120
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...
Definition: fft.F90:814
integer, parameter, public fft_none
global constants
Definition: fft.F90:178
subroutine, public fft_end(this)
Definition: fft.F90:854
subroutine, public fft_init(this, nn, dim, type, library, optimize, optimize_parity, comm, mpi_grp, use_aligned, howmany, nthreads, single)
Definition: fft.F90:452
integer, public fft_default_lib
Definition: fft.F90:284
pure integer function, public pad_feq(ii, nn, mode)
convert between array index and G-vector
Definition: fft.F90:975
integer, parameter, public fftlib_accel
Definition: fft.F90:183
subroutine, public fft_get_dims(fft, rs_n_global, fs_n_global, rs_n, fs_n, rs_istart, fs_istart)
Definition: fft.F90:949
integer, parameter, public fftlib_nfft
Definition: fft.F90:183
integer, parameter, public fftlib_none
Definition: fft.F90:183
integer, parameter, public fftlib_pnfft
Definition: fft.F90:183
integer, parameter, public fftlib_pfft
Definition: fft.F90:183
integer, parameter, public fftlib_fftw
Definition: fft.F90:183
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
real(real64), parameter, public m_one
Definition: global.F90:201
Definition: io.F90:116
subroutine, public mesh_cube_map_end(this)
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
type(mpi_comm), parameter, public mpi_comm_undefined
used to indicate a communicator has not been initialized
Definition: mpi.F90:138
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:338
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
Definition: mpi.F90:407
The low level module to work with the PFFT library. http:
Definition: pfft.F90:128
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
It is intended to be used within a vector.
Definition: cube.F90:198
This is defined even when running serial.
Definition: mpi.F90:144
int true(void)