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#ifdef HAVE_NFFT
38 use nfft_oct_m
39#endif
40 use parser_oct_m
41 use pfft_oct_m
43 use space_oct_m
44
45 implicit none
46 private
47 public :: &
48 cube_t, &
50 cube_init, &
57
58 type cube_t
59 ! Components are public by default
60 logical :: parallel_in_domains
61 type(mpi_grp_t) :: mpi_grp
62
63 integer :: rs_n_global(1:3)
64 integer :: fs_n_global(1:3)
65 integer :: rs_n(1:3)
66 integer :: fs_n(1:3)
67 integer :: rs_istart(1:3)
68 integer :: fs_istart(1:3)
69 integer :: center(1:3)
70
71 real(real64), allocatable :: Lrs(:,:)
72 real(real64), allocatable :: Lfs(:,:)
73
74 integer, allocatable :: np_local(:)
75 integer, allocatable :: xlocal(:)
76 integer, allocatable :: local(:,:)
77 integer, allocatable :: np_local_fs(:)
78 integer, allocatable :: xlocal_fs(:)
79 integer, allocatable :: local_fs(:,:)
80
81
82 type(fft_t), allocatable :: fft
83 logical, private :: has_cube_mapping = .false.
85
86 real(real64) :: spacing(3)
87 ! latt is declared as allocatable as a work-around for a bug in gfortran when invoking the finalizer of latt.
88 type(lattice_vectors_t), allocatable :: latt
89
90 type(mesh_cube_map_t) :: cube_map
91 logical :: cube_map_present = .false.
92 integer :: batch_capacity
95 integer :: batch_axis = 1
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, batch_axis)
113 type(cube_t), intent(out) :: cube
114 integer, intent(in) :: nn(:)
115 type(namespace_t), intent(in) :: namespace
116 class(space_t), intent(in) :: space
117 real(real64), 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 supported FFT solvers, FFTW and PFFT
133 integer, optional, intent(in) :: batch_axis
134 ! every backend), 4 = batch-last (CPU FFTW only). Mirrors fft_t batch_axis.
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)
155 cube%batch_axis = optional_default(batch_axis, 1)
156 ! batch-last is only available on the CPU FFTW path (the only backend with batched batch_axis=4)
157 assert(cube%batch_axis == 1 .or. cube%batch_axis == 4)
159 fft_type_ = optional_default(fft_type, fft_none)
160 tp_enlarge_(:) = (/m_one, m_one, m_one/)
161 if (present(tp_enlarge)) tp_enlarge_(:)=tp_enlarge(:)
163 effdim_fft = min(3, space%dim)
165 mpi_grp_ = mpi_world
166 if (present(mpi_grp)) mpi_grp_ = mpi_grp
168 if (fft_type_ /= fft_none) then
170 if (present(fft_library)) then
171 fft_library_ = fft_library
172 else
173 fft_library_ = fft_default_lib
174 end if
175
176#ifndef HAVE_PFFT
177 if (fft_library_ == fftlib_pfft) then
178 write(message(1),'(a)')'You have selected the PFFT for FFT, but it was not linked.'
179 call messages_fatal(1, namespace=namespace)
180 end if
181#endif
182
183 else
184 fft_library_ = fftlib_none
185 end if
187 ! Note: later we set parallel_in_domains if blocksize is given, too
188 cube%parallel_in_domains = (fft_library_ == fftlib_pfft .or. fft_library_ == fftlib_pnfft)
189 if (present(blocksize)) then
190 assert(present(need_partition).and.need_partition)
191 assert(fft_library_ == fftlib_none)
192 ! For all the different FFT libraries there are strange (?)
193 ! rules about how the decomposition is chosen. What we want
194 ! (for libvdwxc) is a cube parallelized according to the simple
195 ! but contrary rule "just do what I say". Hence the blocksize
196 ! parameter. (Later to be expanded to allow 2D distributions.)
197 cube%rs_n_global = nn3d
198 cube%fs_n_global = nn3d ! not to be used
199 cube%fs_n = cube%fs_n_global ! not to be used
200 cube%fs_istart = 1 ! not to be used
201
202 comm = mpi_grp_%comm
203 cube%parallel_in_domains = (mpi_grp_%size > 1) ! XXX whether comm size > 1
204 call cube_set_blocksize(cube%rs_n_global, blocksize, mpi_grp_%rank, cube%rs_n, cube%rs_istart)
205 else if (fft_library_ == fftlib_none) then
206 cube%rs_n_global = nn3d
207 cube%fs_n_global = nn3d
208 cube%rs_n = cube%rs_n_global
209 cube%fs_n = cube%fs_n_global
210 cube%rs_istart = 1
211 cube%fs_istart = 1
212 comm = mpi_comm_undefined
213 if (present(nn_out)) nn_out(1:3) = nn3d(1:3)
214 else
215 safe_allocate(cube%fft)
216 tmp_n = nn3d
217
218 optimize(1:3) = .false.
219 optimize_parity(1:3) = 0
220 optimize(space%periodic_dim + 1:effdim_fft) = .true.
221 optimize_parity(space%periodic_dim + 1:effdim_fft) = 1
222
223 if (present(dont_optimize)) then
224 if (dont_optimize) optimize = .false.
225 end if
226
227 if (present(tp_enlarge)) call cube_tp_fft_defaults(cube, fft_library_)
228
229 call fft_init(cube%fft, tmp_n, space%dim, fft_type_, fft_library_, optimize, optimize_parity, &
230 comm=comm, mpi_grp = mpi_grp_, use_aligned=.true., howmany=cube%batch_capacity, &
231 batch_axis=cube%batch_axis)
232 if (present(nn_out)) nn_out(1:3) = tmp_n(1:3)
233
234 call fft_get_dims(cube%fft, cube%rs_n_global, cube%fs_n_global, cube%rs_n, cube%fs_n, &
235 cube%rs_istart, cube%fs_istart)
236
237 if (present(tp_enlarge)) then
238 call cube_init_coords(cube, tp_enlarge_, cube%spacing, fft_library_)
239 end if
240
241 if (fft_library_ == fftlib_nfft .or. fft_library_ == fftlib_pnfft) then
242 call fft_init_stage1(cube%fft, namespace, cube%Lrs, cube%rs_n_global)
243 !set local dimensions after stage1 - needed for PNFFT
244 call fft_get_dims(cube%fft, cube%rs_n_global, cube%fs_n_global, cube%rs_n, cube%fs_n, &
245 cube%rs_istart, cube%fs_istart)
246 end if
247
248 end if
249
250 if (.not. allocated(cube%Lrs)) then
251 call cube_init_coords(cube, tp_enlarge_, cube%spacing, fft_library_)
252 end if
253
254
255 cube%center(1:3) = cube%rs_n_global(1:3)/2 + 1
256
257
258 call mpi_grp_init(cube%mpi_grp, comm)
259
260 ! Initialize mapping only if needed
261 if (present(need_partition) .and. cube%parallel_in_domains) then
262 cube%has_cube_mapping = need_partition
263 else
264 cube%has_cube_mapping = .false.
265 end if
266 if (cube%has_cube_mapping) then
267 call cube_do_mapping(cube, fs = fft_library_ == fftlib_pnfft)
268 end if
269
270 if (cube%parallel_in_domains) call cube_partition_messages_debug(cube, namespace)
271
272 select type (coord_system)
273 class is (affine_coordinates_t)
274 ! We are constructing a lattice vector for the cube
275 ! This differs from the actual lattice vectors if it is not an integer multiple of the spacing
276 ! mesh%idx%ll is "general" in aperiodic directions,
277 ! but "periodic" in periodic directions.
278 my_n(1:space%periodic_dim) = cube%rs_n_global(1:space%periodic_dim) + 1
279 my_n(space%periodic_dim + 1:space%dim) = cube%rs_n_global(space%periodic_dim + 1:space%dim)
280
281 lattice_vectors = m_zero
282 do idir = 1, space%dim
283 do idir2 = 1, space%dim
284 lattice_vectors(idir2, idir) = cube%spacing(idir) * (my_n(idir) - 1) * coord_system%basis%vectors(idir2, idir)
285 end do
286 end do
287 do idir = space%dim + 1, 3
288 lattice_vectors(idir, idir) = m_one
289 end do
290
291 cube_space%dim = 3
292 cube_space%periodic_dim = space%periodic_dim
293 safe_allocate(cube%latt)
294 cube%latt = lattice_vectors_t(namespace, cube_space, lattice_vectors)
295 class default
296 message(1) = "The cube only support affine coordinate systems."
297 call messages_fatal(1, namespace=namespace)
298 end select
299
300 pop_sub(cube_init)
301 end subroutine cube_init
302
303 ! ---------------------------------------------------------
304 subroutine cube_end(cube)
305 type(cube_t), intent(inout) :: cube
306
307 push_sub(cube_end)
308
309 if (allocated(cube%fft)) then
310 call fft_end(cube%fft)
311 safe_deallocate_a(cube%fft)
312 end if
313
314 if (cube%has_cube_mapping) then
315 safe_deallocate_a(cube%np_local)
316 safe_deallocate_a(cube%xlocal)
317 safe_deallocate_a(cube%local)
318
319 safe_deallocate_a(cube%np_local_fs)
320 safe_deallocate_a(cube%xlocal_fs)
321 safe_deallocate_a(cube%local_fs)
322 end if
323
324 if (cube%cube_map_present) then
325 call mesh_cube_map_end(cube%cube_map)
326 end if
327
328 safe_deallocate_a(cube%Lrs)
329 safe_deallocate_a(cube%Lfs)
330
331 safe_deallocate_a(cube%latt)
332
333 pop_sub(cube_end)
334 end subroutine cube_end
335
336
337 ! ---------------------------------------------------------
338 subroutine cube_tp_fft_defaults(cube, fft_library)
339 type(cube_t), intent(inout) :: cube
340 integer, intent(in) :: fft_library
341
342 push_sub(cube_tp_fft_defaults)
343 select case (fft_library)
344 case (fftlib_nfft)
345#ifdef HAVE_NFFT
346 !Set NFFT defaults to values that gives good performance for two-point enlargement
347 !These values are overridden by the NFFT options in the input file
348 cube%fft%nfft%set_defaults = .true.
349 cube%fft%nfft%guru = .true.
350 cube%fft%nfft%mm = 2
351 cube%fft%nfft%sigma = 1.1_real64
352 cube%fft%nfft%precompute = nfft_pre_psi
353#endif
354 case (fftlib_pnfft)
355 cube%fft%pnfft%set_defaults = .true.
356 cube%fft%pnfft%m = 2
357 cube%fft%pnfft%sigma = 1.1_real64
358
359 case default
360 !do nothing
361 end select
362
363 pop_sub(cube_tp_fft_defaults)
364 end subroutine cube_tp_fft_defaults
365
366
367 ! ---------------------------------------------------------
368 subroutine cube_init_coords(cube, tp_enlarge, spacing, fft_library)
369 type(cube_t), intent(inout) :: cube
370 real(real64), intent(in) :: tp_enlarge(3)
371 real(real64), intent(in) :: spacing(3)
372 integer, intent(in) :: fft_library
373
374 real(real64) :: temp
375 integer :: ii, nn(3), maxn, idim
376
377 push_sub(cube_init_coords)
378
379
380 nn(1:3) = cube%fs_n_global(1:3)
381
382 maxn = maxval(nn)
383 safe_allocate(cube%Lrs(1:maxn, 1:3))
384 cube%Lrs(:,:) = m_zero
385
386 !! Real space coordinates
387 do idim = 1,3
388 if (tp_enlarge(idim) > m_one) then
389 do ii = 2, nn(idim) - 1
390 cube%Lrs(ii, idim) = (ii - int(nn(idim)/2) -1) * spacing(idim)
391 end do
392 cube%Lrs(1, idim) = (-int(nn(idim)/2)) * spacing(idim) * tp_enlarge(idim)
393 cube%Lrs(nn(idim), idim) = (int(nn(idim)/2)) * spacing(idim) * tp_enlarge(idim)
394 else
395 do ii = 1, nn(idim)
396 cube%Lrs(ii, idim) = (ii - int(nn(idim)/2) -1) * spacing(idim)
397 end do
398 end if
399 end do
400
401
402 !! Fourier space coordinates
403 if (fft_library /= fftlib_none) then
404
405 safe_allocate(cube%Lfs(1:maxn, 1:3))
406 cube%Lfs(:,:) = m_zero
407
408 do idim = 1,3
409 temp = m_two * m_pi / (nn(idim) * spacing(idim))
410!temp = M_PI / (nn * spacing(1))
411 do ii = 1, nn(idim)
412 if (fft_library == fftlib_nfft .or. fft_library == fftlib_pnfft) then
413 !The Fourier space is shrunk by the tp_enlarge factor
414 !cube%Lfs(ii, 1:3) = (ii - nn/2 - 1)*temp/tp_enlarge
415!HH NOTE:
416!not sure this is the right general factor
417 cube%Lfs(ii, idim) = (ii - nn(idim)/2 - 1)*temp/tp_enlarge(idim)
418 else
419 cube%Lfs(ii, idim) = pad_feq(ii,nn(idim), .true.) * temp
420 end if
421 end do
422 end do
423 end if
424
425 pop_sub(cube_init_coords)
426 end subroutine cube_init_coords
427
428
429 ! ---------------------------------------------------------
432 logical function cube_global2local(cube, ixyz, lxyz) result(is_here)
433 type(cube_t), intent(in) :: cube
434 integer, intent(in) :: ixyz(3)
435 integer, intent(out) :: lxyz(3)
436
437 lxyz(1) = ixyz(1) - cube%rs_istart(1) + 1
438 lxyz(2) = ixyz(2) - cube%rs_istart(2) + 1
439 lxyz(3) = ixyz(3) - cube%rs_istart(3) + 1
440 is_here = lxyz(1) >= 1 .and. lxyz(1) <= cube%rs_n(1) .and. &
441 lxyz(2) >= 1 .and. lxyz(2) <= cube%rs_n(2) .and. &
442 lxyz(3) >= 1 .and. lxyz(3) <= cube%rs_n(3)
443
444 end function cube_global2local
445
446
447 ! ---------------------------------------------------------
452 integer function cube_getfftlibrary(cube) result(fft_library)
453 type(cube_t), intent(in) :: cube
454
455 if (allocated(cube%fft)) then
456 fft_library = cube%fft%library
457 else
458 fft_library = fftlib_none
459 end if
460 end function cube_getfftlibrary
461
462 ! ---------------------------------------------------------
464 subroutine cube_do_mapping(cube, fs)
465 type(cube_t), intent(inout) :: cube
466 logical, intent(in) :: fs
467
468 integer :: tmp_local(6), position, process, ix, iy, iz, index
469 integer, allocatable :: local_sizes(:)
470 integer(int64) :: number_points
471
472 push_sub(cube_do_mapping)
473
474 !!BEGIN:gather the local information into a unique vector.
475 !!do a gather in 3d of all the box, into a loop
476 tmp_local(1) = cube%rs_istart(1)
477 tmp_local(2) = cube%rs_istart(2)
478 tmp_local(3) = cube%rs_istart(3)
479 tmp_local(4) = cube%rs_n(1)
480 tmp_local(5) = cube%rs_n(2)
481 tmp_local(6) = cube%rs_n(3)
482
483 if (cube%parallel_in_domains) then
484 safe_allocate(local_sizes(1:6*cube%mpi_grp%size))
485 call profiling_in("CUBE_GAT")
486 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
487 call profiling_out("CUBE_GAT")
488 else
489 safe_allocate(local_sizes(1:6))
490 local_sizes = tmp_local
491 end if
492
493 call profiling_in("CUBE_MAP")
494
495 safe_allocate(cube%xlocal(1:cube%mpi_grp%size))
496 safe_allocate(cube%np_local(1:cube%mpi_grp%size))
497 ! make sure we do not run into integer overflow here
498 number_points = cube%rs_n_global(1) * cube%rs_n_global(2)
499 number_points = number_points * cube%rs_n_global(3)
500 if (number_points >= huge(0)) then
501 message(1) = "Error: too many points for the normal cube. Please try to use a distributed FFT."
502 call messages_fatal(1)
503 end if
504 safe_allocate(cube%local(1:cube%rs_n_global(1)*cube%rs_n_global(2)*cube%rs_n_global(3), 1:3))
505
506 index = 1
507 do process = 1, cube%mpi_grp%size
508 position = ((process-1)*6)+1
509 if (position == 1) then
510 cube%xlocal(1) = 1
511 cube%np_local(1) = local_sizes(4)*local_sizes(5)*local_sizes(6)
512 else
513 ! calculate the begin index and size of each process
514 cube%xlocal(process) = cube%xlocal(process-1) + cube%np_local(process-1)
515 cube%np_local(process) = local_sizes(position+3)*local_sizes(position+4)*local_sizes(position+5)
516 end if
517
518 ! save the mapping between the global x,y,z and the global index
519 ! and determine which partition the point belongs to
520 do iz = local_sizes(position+2), local_sizes(position+2)+local_sizes(position+5)-1
521 do iy = local_sizes(position+1), local_sizes(position+1)+local_sizes(position+4)-1
522 do ix = local_sizes(position), local_sizes(position)+local_sizes(position+3)-1
523 cube%local(index, 1) = ix
524 cube%local(index, 2) = iy
525 cube%local(index, 3) = iz
526 index = index + 1
527 end do
528 end do
529 end do
530 end do
531
532 call profiling_out("CUBE_MAP")
533
534 if (optional_default(fs,.false.)) then
535
536 tmp_local(1) = cube%fs_istart(1)
537 tmp_local(2) = cube%fs_istart(2)
538 tmp_local(3) = cube%fs_istart(3)
539 tmp_local(4) = cube%fs_n(1)
540 tmp_local(5) = cube%fs_n(2)
541 tmp_local(6) = cube%fs_n(3)
542
543 local_sizes = 0
544 if (cube%parallel_in_domains) then
545 call profiling_in("CUBE_GAT_FS")
546 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
547 call profiling_out("CUBE_GAT_FS")
548 else
549 local_sizes = tmp_local
550 end if
552 call profiling_in("CUBE_MAP_FS")
553
554 safe_allocate(cube%xlocal_fs(1:cube%mpi_grp%size))
555 safe_allocate(cube%np_local_fs(1:cube%mpi_grp%size))
556 ! make sure we do not run into integer overflow here
557 number_points = cube%fs_n_global(1) * cube%fs_n_global(2)
558 number_points = number_points * cube%fs_n_global(3)
559 if (number_points >= huge(0)) then
560 message(1) = "Error: too many points for the normal cube. Please try to use a distributed FFT."
561 call messages_fatal(1)
562 end if
563 safe_allocate(cube%local_fs(1:cube%fs_n_global(1)*cube%fs_n_global(2)*cube%fs_n_global(3), 1:3))
564
565 index = 1
566 do process = 1, cube%mpi_grp%size
567 position = ((process-1)*6)+1
568 if (position == 1) then
569 cube%xlocal_fs(1) = 1
570 cube%np_local_fs(1) = local_sizes(4)*local_sizes(5)*local_sizes(6)
571 else
572 ! calculate the begin index and size of each process
573 cube%xlocal_fs(process) = cube%xlocal_fs(process-1) + cube%np_local_fs(process-1)
574 cube%np_local_fs(process) = local_sizes(position+3)*local_sizes(position+4)*local_sizes(position+5)
575 end if
576
577 ! save the mapping between the global x,y,z and the global index
578 ! and determine which partition the point belongs to
579 do iz = local_sizes(position+2), local_sizes(position+2)+local_sizes(position+5)-1
580 do iy = local_sizes(position+1), local_sizes(position+1)+local_sizes(position+4)-1
581 do ix = local_sizes(position), local_sizes(position)+local_sizes(position+3)-1
582 cube%local_fs(index, 1) = ix
583 cube%local_fs(index, 2) = iy
584 cube%local_fs(index, 3) = iz
585 index = index + 1
586 end do
587 end do
588 end do
589 end do
590
591 call profiling_out("CUBE_MAP_FS")
592
593 end if
594
595
596
597 safe_deallocate_a(local_sizes)
598
599 pop_sub(cube_do_mapping)
600 end subroutine cube_do_mapping
601
602 !!> Given a x, y, z point of the cube, it returns the corresponding process
603 !!
604 !! last_found is used to speed-up the search
605 integer pure function cube_point_to_process(mpi_grp, xyz, part) result(process)
606 type(mpi_grp_t), intent(in) :: mpi_grp
607 integer, intent(in) :: xyz(1:3)
608 type(dimensions_t), intent(in) :: part(:)
609
610 integer :: proc
611 logical :: found
612
613 ! No PUSH/POP because it is a PURE function
614
615 found = .false.
616 do proc = 1, mpi_grp%size
617 !Compare XYZ index
618 if (all(xyz >= part(proc)%start_xyz) .and. all(xyz <= part(proc)%end_xyz)) then
619 process = proc
620 found = .true.
621 exit
622 end if
623 end do
624
625 ! An error message should be raised, if this point is reached
626 if (.not. found) then
627 process = -1
628 end if
629
630 end function cube_point_to_process
631
632 ! Sets a 1D decomposition with fixed-size blocks over the last (least-contiguous) axis.
633 ! Each core will have <blocksize> slices except the last one which will typically have
634 ! less. (In some cases, there can be multiple trailing cores without any slices.)
635 subroutine cube_set_blocksize(rs_n_global, blocksize, rank, rs_n, rs_istart)
636 integer, intent(in) :: rs_n_global(1:3)
637 integer, intent(in) :: blocksize
638 integer, intent(in) :: rank
639 integer, intent(out) :: rs_n(1:3)
640 integer, intent(out) :: rs_istart(1:3)
641
642 integer :: imin, imax
643
644 rs_n = rs_n_global
645 rs_istart = 1
646
647 imin = min(blocksize * rank, rs_n_global(3))
648 imax = min(imin + blocksize, rs_n_global(3))
649 rs_istart(3) = 1 + imin
650 rs_n(3) = imax - imin
651 end subroutine cube_set_blocksize
652
653 ! ---------------------------------------------------------
654 subroutine cube_partition(cube, part)
655 type(cube_t), intent(in) :: cube
656 type(dimensions_t), intent(out) :: part(:)
657
658 integer :: tmp_local(6), position, process
659 integer, allocatable :: local_sizes(:)
660
661 push_sub(cube_partition)
662
663 !!gather the local information into a unique vector.
664 tmp_local(1) = cube%rs_istart(1)
665 tmp_local(2) = cube%rs_istart(2)
666 tmp_local(3) = cube%rs_istart(3)
667 tmp_local(4) = cube%rs_n(1)
668 tmp_local(5) = cube%rs_n(2)
669 tmp_local(6) = cube%rs_n(3)
670
671 if (cube%parallel_in_domains) then
672 safe_allocate(local_sizes(1:6*cube%mpi_grp%size))
673 call cube%mpi_grp%allgather(tmp_local, 6, mpi_integer, local_sizes, 6, mpi_integer)
674 else
675 safe_allocate(local_sizes(1:6))
676 local_sizes(:) = tmp_local(:)
677 end if
678
679 do process = 1, cube%mpi_grp%size
680 position = ((process-1)*6)+1
681
682 part(process)%start_xyz(1) = local_sizes(position)
683 part(process)%start_xyz(2) = local_sizes(position+1)
684 part(process)%start_xyz(3) = local_sizes(position+2)
685 part(process)%end_xyz(1) = local_sizes(position)+local_sizes(position+3)-1
686 part(process)%end_xyz(2) = local_sizes(position+1)+local_sizes(position+4)-1
687 part(process)%end_xyz(3) = local_sizes(position+2)+local_sizes(position+5)-1
688
689 end do
690
691 pop_sub(cube_partition)
692 end subroutine cube_partition
693
694 ! ---------------------------------------------------------
695 subroutine cube_partition_messages_debug(cube, namespace)
696 type(cube_t), intent(in) :: cube
697 type(namespace_t), intent(in) :: namespace
698
699 integer :: nn, ii, jj, kk ! Counters.
700 integer :: ixyz(3) ! Current value of xyz
701 integer :: npart
702 integer :: iunit ! For debug output to files.
703 character(len=3) :: filenum
704 type(dimensions_t), allocatable :: part(:)
705
707
708 if (debug%info) then
709 safe_allocate(part(1:cube%mpi_grp%size))
710 call cube_partition(cube, part)
711
712 if (mpi_world%is_root()) then
713 call io_mkdir('debug/cube_partition', namespace)
714 npart = cube%mpi_grp%size
715
716 ! Debug output. Write points of each partition in a different file.
717 do nn = 1, npart
718
719 write(filenum, '(i3.3)') nn
720
721 iunit = io_open('debug/cube_partition/cube_partition.'//filenum, &
722 namespace, action='write')
723 do kk = 1, cube%rs_n_global(3)
724 do jj = 1, cube%rs_n_global(2)
725 do ii = 1, cube%rs_n_global(1)
726 ixyz(1) = ii
727 ixyz(2) = jj
728 ixyz(3) = kk
729 if (cube_point_to_process(cube%mpi_grp, ixyz, part) == nn) then
730 write(iunit, '(3i8)') ii, jj, kk
731 end if
732 end do
733 end do
734 end do
735 call io_close(iunit)
736 end do
737
738
739 end if
740
741 safe_deallocate_a(part)
742 end if
743
744 call cube%mpi_grp%barrier()
745
747 end subroutine cube_partition_messages_debug
748
749 ! ---------------------------------------------------------
750 subroutine cube_init_cube_map(cube, mesh)
751 type(cube_t), intent(inout) :: cube
752 class(mesh_t), intent(in) :: mesh
753
754 push_sub(cube_init_cube_map)
755
756 call mesh_cube_map_init(cube%cube_map, mesh, mesh%np)
757 cube%cube_map_present = .true.
758
759 pop_sub(cube_init_cube_map)
760 end subroutine cube_init_cube_map
761end module cube_oct_m
762
763
764!! Local Variables:
765!! mode: f90
766!! coding: utf-8
767!! End:
subroutine cube_set_blocksize(rs_n_global, blocksize, rank, rs_n, rs_istart)
Definition: cube.F90:723
subroutine cube_do_mapping(cube, fs)
do the mapping between global and local points of the cube
Definition: cube.F90:552
subroutine, public cube_end(cube)
Definition: cube.F90:400
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:520
subroutine cube_tp_fft_defaults(cube, fft_library)
Definition: cube.F90:434
integer pure function, public cube_point_to_process(mpi_grp, xyz, part)
Definition: cube.F90:693
integer function, public cube_getfftlibrary(cube)
Returns the FFT library of the cube. Possible values are FFTLIB_NONE, FFTLIB_FFTW,...
Definition: cube.F90:540
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, batch_axis)
Definition: cube.F90:208
subroutine cube_init_coords(cube, tp_enlarge, spacing, fft_library)
Definition: cube.F90:456
subroutine, public cube_partition(cube, part)
Definition: cube.F90:742
subroutine, public cube_init_cube_map(cube, mesh)
Definition: cube.F90:838
subroutine cube_partition_messages_debug(cube, namespace)
Definition: cube.F90:783
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:120
integer, parameter, public fft_none
global constants
Definition: fft.F90:174
subroutine, public fft_end(this)
Definition: fft.F90:818
integer, public fft_default_lib
Definition: fft.F90:264
pure integer function, public pad_feq(ii, nn, mode)
convert between array index and G-vector
Definition: fft.F90:942
subroutine, public fft_get_dims(fft, rs_n_global, fs_n_global, rs_n, fs_n, rs_istart, fs_istart)
Definition: fft.F90:916
integer, parameter, public fftlib_nfft
Definition: fft.F90:179
integer, parameter, public fftlib_none
Definition: fft.F90:179
integer, parameter, public fftlib_pnfft
Definition: fft.F90:179
subroutine, public fft_init(this, nn, dim, type, library, optimize, optimize_parity, comm, mpi_grp, use_aligned, howmany, batch_axis)
Definition: fft.F90:415
integer, parameter, public fftlib_pfft
Definition: fft.F90:179
subroutine, public fft_init_stage1(this, namespace, XX, nn)
Some fft-libraries (only NFFT for the moment) need an additional precomputation stage that depends on...
Definition: fft.F90:776
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:272
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
Definition: mpi.F90:341
integer, parameter, public nfft_pre_psi
Definition: nfft.F90:150
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)