Octopus
par_vec.F90
Go to the documentation of this file.
1!! Copyright (C) 2005-2006 Florian Lorenzen, Heiko Appel, J. Alberdi-Rodriguez
2!! Copyright (C) 2021 Sebastian Ohlmann
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
78module par_vec_oct_m
79 use accel_oct_m
80 use debug_oct_m
81 use global_oct_m
82 use iihash_oct_m
83 use index_oct_m
84 use io_oct_m
86 use mpi_oct_m
89 use parser_oct_m
92 use sort_oct_m
93 use space_oct_m
95 use types_oct_m
96 use utils_oct_m
97
98 implicit none
99
100 private
101
102 public :: &
103 par_vec_t, &
104 par_vec_init, &
105 par_vec_end, &
111
116 !
117 type par_vec_t
118 ! Components are public by default
119
120 ! The content of these members is process-dependent.
121 integer :: rank
122 integer :: partno
123 integer, allocatable :: ghost_sendpos(:)
124
125 integer, allocatable :: ghost_rdispls(:)
126 integer, allocatable :: ghost_sdispls(:)
127 integer, allocatable :: ghost_rcounts(:)
128 integer, allocatable :: ghost_scounts(:)
129 integer :: ghost_scount
130 integer, allocatable :: ghost_sendmap(:)
131 integer, allocatable :: ghost_recvmap(:)
132 type(accel_mem_t) :: buff_sendmap
133 type(accel_mem_t) :: buff_recvmap
134
135 ! The following members are set independent of the processs.
136 type(mpi_grp_t) :: mpi_grp
137 integer :: npart
138 integer(int64) :: np_global
139
140 integer, allocatable :: np_local_vec(:)
142 integer :: np_local
144 integer(int64), allocatable, private :: xlocal_vec(:)
148 integer(int64) :: xlocal
150
151 integer(int64), allocatable, private :: local(:)
153 integer, allocatable :: recv_count(:)
154 integer, allocatable :: send_count(:)
156 integer, allocatable :: recv_disp(:)
157 integer, allocatable :: send_disp(:)
158 integer(int64), allocatable:: sendmap(:)
159 integer(int64), allocatable:: recvmap(:)
161 integer :: np_bndry
162
163 integer(int64), allocatable, private :: bndry(:)
164
165 type(lihash_t), private :: global
166
167 integer :: np_ghost
168 integer(int64), allocatable, private :: ghost(:)
169 end type par_vec_t
170
171 interface par_vec_scatter
172 module procedure dpar_vec_scatter
173 module procedure zpar_vec_scatter
174 module procedure ipar_vec_scatter
175 module procedure spar_vec_scatter
176 module procedure cpar_vec_scatter
177 end interface par_vec_scatter
178
179 interface par_vec_gather
180 module procedure dpar_vec_gather
181 module procedure zpar_vec_gather
182 module procedure ipar_vec_gather
183 module procedure spar_vec_gather
184 module procedure cpar_vec_gather
185 end interface par_vec_gather
186
187 interface par_vec_allgather
188 module procedure dpar_vec_allgather
189 module procedure zpar_vec_allgather
190 module procedure ipar_vec_allgather
191 module procedure spar_vec_allgather
192 module procedure cpar_vec_allgather
193 end interface par_vec_allgather
194
195contains
196
205 !
206 subroutine par_vec_init(mpi_grp, np_global, idx, stencil, space, partition, pv, namespace)
207 type(mpi_grp_t), intent(in) :: mpi_grp
208 ! The next seven entries come from the mesh.
209 integer(int64), intent(in) :: np_global
210 type(index_t), intent(in) :: idx
211 type(stencil_t), intent(in) :: stencil
212 class(space_t), intent(in) :: space
213 type(partition_t), intent(in) :: partition
214 type(par_vec_t), intent(inout) :: pv
215 type(namespace_t), intent(in) :: namespace
217 ! Careful: MPI counts process ranks from 0 to numproc-1.
218 ! Partition numbers from METIS range from 1 to numproc.
219 ! For this reason, all ranks are incremented by one.
220 integer :: npart
221 integer(int64) :: gip, index
222 integer :: ip, jp, jj, inode
223 integer :: p1(space%dim)
224 type(lihash_t) :: boundary
225 type(lihash_t) :: ghost
226 integer(int64), allocatable :: boundary_inv(:), ghost_inv(:)
227 integer :: iunit
228 character(len=6) :: filenum
229 logical :: found
230
231 integer :: idir, ipart, itmp
232 integer(int64) :: tmp
233 integer, allocatable :: points(:), part_ghost(:), part_ghost_tmp(:)
234 integer(int64), allocatable :: indices(:), ghost_tmp(:)
236 push_sub(par_vec_init)
238 ! Shortcuts.
239 npart = mpi_grp%size
240
241 ! Store partition number and rank for later reference.
242 ! Having both variables is a bit redundant but makes the code readable.
243 pv%rank = mpi_grp%rank
244 pv%partno = pv%rank + 1
245
246 call mpi_grp_copy(pv%mpi_grp, mpi_grp)
247 pv%np_global = np_global
248 pv%npart = npart
250
251 safe_allocate(pv%np_local_vec(1:npart))
252 safe_allocate(pv%xlocal_vec(1:npart))
253 safe_allocate(pv%ghost_rcounts(1:npart))
254 safe_allocate(pv%ghost_scounts(1:npart))
255
256 ! Count number of points for each process.
257 ! Local points.
258 call partition_get_np_local(partition, pv%np_local_vec)
259 pv%np_local = pv%np_local_vec(pv%partno)
261
262 ! Set up local-to-global index table for local points (xlocal_vec, local)
263 pv%xlocal_vec(1) = 1
264 ! Set the starting point of local and boundary points
265 do inode = 2, npart
266 pv%xlocal_vec(inode) = pv%xlocal_vec(inode - 1) + pv%np_local_vec(inode - 1)
267 end do
268 pv%xlocal = pv%xlocal_vec(pv%partno)
269
270 safe_allocate(pv%local(pv%xlocal:pv%xlocal + pv%np_local - 1))
271 ! Calculate the local vector in parallel
272 call partition_get_local(partition, pv%local(pv%xlocal:), itmp)
273
274 ! Create hash table.
275 call lihash_init(pv%global)
276 ! Insert local points.
277 do ip = 1, pv%np_local
278 call lihash_insert(pv%global, pv%local(pv%xlocal + ip - 1), ip)
279 end do
280
281 ! reorder points if needed
283
284 call lihash_init(boundary)
285 call lihash_init(ghost)
286 safe_allocate(boundary_inv(1:pv%np_local))
287 safe_allocate(ghost_inv(1:pv%np_local))
288 pv%np_ghost = 0
289 pv%np_bndry = 0
290 do gip = pv%xlocal, pv%xlocal + pv%np_local - 1
291 ! Get coordinates of current point.
292 call index_to_coords(idx, pv%local(gip), p1)
293 ! For all points in stencil.
294 do jj = 1, stencil%size
295 ! Get point number of possible ghost point.
296 index = index_from_coords(idx, p1(:) + stencil%points(:, jj))
297 assert(index /= 0)
298 ! check if this point is a local point
299 tmp = lihash_lookup(pv%global, index, found)
300 if (found) cycle
301 ! now check if the point is a potential ghost or boundary point
302 if (index > np_global) then
303 tmp = lihash_lookup(boundary, index, found)
304 if (found) cycle
305 pv%np_bndry = pv%np_bndry + 1
306 call lihash_insert(boundary, index, pv%np_bndry)
307 if (pv%np_bndry >= ubound(boundary_inv, 1)) call make_array_larger(boundary_inv, pv%np_bndry*2)
308 boundary_inv(pv%np_bndry) = index
309 else
310 tmp = lihash_lookup(ghost, index, found)
311 if (found) cycle
312 pv%np_ghost = pv%np_ghost + 1
313 call lihash_insert(ghost, index, pv%np_ghost)
314 if (pv%np_ghost >= ubound(ghost_inv, 1)) call make_array_larger(ghost_inv, pv%np_ghost*2)
315 ghost_inv(pv%np_ghost) = index
316 end if
317 end do
318 end do
319
320 safe_allocate(pv%bndry(1:pv%np_bndry))
321 do ip = 1, pv%np_bndry
322 pv%bndry(ip) = boundary_inv(ip)
323 end do
324
325 ! first get the temporary array of ghost points, will be later reorder by partition
326 safe_allocate(ghost_tmp(1:pv%np_ghost))
327 do ip = 1, pv%np_ghost
328 ghost_tmp(ip) = ghost_inv(ip)
329 end do
330 call lihash_end(ghost)
331 call lihash_end(boundary)
332 safe_deallocate_a(ghost_inv)
333 safe_deallocate_a(boundary_inv)
334
335 safe_allocate(part_ghost_tmp(1:pv%np_ghost))
336 call partition_get_partition_number(partition, pv%np_ghost, &
337 ghost_tmp, part_ghost_tmp)
338
339 ! determine parallel distribution (counts, displacements)
340 pv%ghost_rcounts(:) = 0
341 do ip = 1, pv%np_ghost
342 ipart = part_ghost_tmp(ip)
343 pv%ghost_rcounts(ipart) = pv%ghost_rcounts(ipart)+1
344 end do
345 assert(sum(pv%ghost_rcounts) == pv%np_ghost)
346
347 safe_allocate(pv%ghost_rdispls(1:pv%npart))
348 pv%ghost_rdispls(1) = 0
349 do ipart = 2, pv%npart
350 pv%ghost_rdispls(ipart) = pv%ghost_rdispls(ipart - 1) + pv%ghost_rcounts(ipart - 1)
351 end do
352
353 ! reorder points by partition
354 safe_allocate(pv%ghost(1:pv%np_ghost))
355 safe_allocate(part_ghost(1:pv%np_ghost))
356 safe_allocate(points(1:pv%npart))
357 points = 0
358 do ip = 1, pv%np_ghost
359 ipart = part_ghost_tmp(ip)
360 points(ipart) = points(ipart)+1
361 ! jp is the new index, sorted according to partitions
362 jp = pv%ghost_rdispls(ipart) + points(ipart)
363 pv%ghost(jp) = ghost_tmp(ip)
364 part_ghost(jp) = part_ghost_tmp(ip)
365 end do
366 safe_deallocate_a(points)
367 safe_deallocate_a(ghost_tmp)
368 safe_deallocate_a(part_ghost_tmp)
369
370 call pv%mpi_grp%alltoall(pv%ghost_rcounts, 1, mpi_integer, &
371 pv%ghost_scounts, 1, mpi_integer)
372
373 safe_allocate(pv%ghost_sdispls(1:pv%npart))
374
375 pv%ghost_sdispls(1) = 0
376 do ipart = 2, pv%npart
377 pv%ghost_sdispls(ipart) = pv%ghost_sdispls(ipart - 1) + pv%ghost_scounts(ipart - 1)
378 end do
379 pv%ghost_scount = sum(pv%ghost_scounts)
380
381 safe_allocate(pv%ghost_recvmap(1:pv%np_ghost))
382 safe_allocate(points(1:pv%npart))
383 points = 0
384 do ip = 1, pv%np_ghost
385 ipart = part_ghost(ip)
386 points(ipart) = points(ipart) + 1
387 pv%ghost_recvmap(ip) = pv%ghost_rdispls(ipart) + points(ipart)
388 end do
389 safe_deallocate_a(points)
390
391 safe_allocate(indices(1:pv%np_ghost))
392 do ip = 1, pv%np_ghost
393 indices(pv%ghost_recvmap(ip)) = pv%ghost(ip)
394 end do
395 safe_allocate(pv%ghost_sendmap(1:pv%ghost_scount))
396 safe_allocate(ghost_tmp(1:pv%ghost_scount))
397 call pv%mpi_grp%alltoallv(indices, pv%ghost_rcounts, pv%ghost_rdispls, mpi_integer8, &
398 ghost_tmp, pv%ghost_scounts, pv%ghost_sdispls, mpi_integer8)
399 do ip = 1, pv%ghost_scount
400 ! get local index
401 jp = lihash_lookup(pv%global, ghost_tmp(ip), found)
402 assert(found)
403 pv%ghost_sendmap(ip) = jp
404 end do
405 safe_deallocate_a(indices)
406 safe_deallocate_a(ghost_tmp)
407
408 if (accel_is_enabled()) then
409 ! copy maps to GPU
410 call accel_create_buffer(pv%buff_sendmap, accel_mem_read_only, type_integer, pv%ghost_scount)
411 call accel_write_buffer(pv%buff_sendmap, pv%ghost_scount, pv%ghost_sendmap)
412
413 call accel_create_buffer(pv%buff_recvmap, accel_mem_read_only, type_integer, pv%np_ghost)
414 call accel_write_buffer(pv%buff_recvmap, pv%np_ghost, pv%ghost_recvmap)
415 end if
416
417 if (debug%info) then
418 ! Write numbers and coordinates of each process` ghost points
419 ! to a single file (like in mesh_partition_init) called
420 ! debug/mesh_partition/ghost_points.###.
421 call io_mkdir('debug/mesh_partition', namespace, parents=.true.)
422
423 write(filenum, '(i6.6)') pv%partno
424 iunit = io_open('debug/mesh_partition/ghost_points.'//filenum, namespace, action='write')
425 do ip = 1, pv%np_ghost
426 call index_to_coords(idx, pv%ghost(ip), p1)
427 write(iunit, '(99i8)') pv%ghost(ip), (p1(idir), idir = 1, space%dim)
428 end do
429
430 call io_close(iunit)
431 end if
432
433 call init_mpi_alltoall()
434
435 ! Insert ghost points.
436 do ip = 1, pv%np_ghost
437 call lihash_insert(pv%global, pv%ghost(ip), ip + pv%np_local)
438 end do
439 ! Insert boundary points.
440 do ip = 1, pv%np_bndry
441 call lihash_insert(pv%global, pv%bndry(ip), ip + pv%np_local + pv%np_ghost)
442 end do
443
444 safe_deallocate_a(part_ghost)
445
446 pop_sub(par_vec_init)
447
448 contains
449 subroutine reorder_points()
450 integer :: ip, nn, direction
451 integer(int64) :: ipg
452 integer :: bsize(space%dim), order, point(space%dim), number_of_blocks(space%dim)
453 integer(int64), allocatable :: reorder_indices(:)
454 integer(int64), allocatable :: reordered(:)
455 integer, allocatable :: global_indices(:)
456 type(block_t) :: blk
457 logical :: increase_with_dimension
458 integer, parameter :: &
459 order_blocks = 1, &
460 order_cube = 3, &
461 order_global = 4
462
464
465 !%Variable MeshLocalOrder
466 !%Default blocks
467 !%Type integer
468 !%Section Execution::Optimization
469 !%Description
470 !% This variable controls how the grid points are mapped to a
471 !% linear array. This influences the performance of the code.
472 !%Option order_blocks 1
473 !% The grid is mapped using small parallelepipedic grids. The size
474 !% of the blocks is controlled by <tt>MeshBlockSize</tt>.
475 !%Option order_cube 3
476 !% The grid is mapped using a full cube, i.e. without blocking.
477 !%Option order_global 4
478 !% Use the ordering from the global mesh
479 !%End
480 call parse_variable(namespace, 'MeshLocalOrder', order_blocks, order)
481 ! no reordering in 1D necessary
482 if (space%dim == 1) then
483 order = order_global
484 end if
485
486 !%Variable MeshLocalBlockDirection
487 !%Type integer
488 !%Section Execution::Optimization
489 !%Description
490 !% Determines the direction in which the dimensions are chosen to compute
491 !% the blocked index for sorting the mesh points (see MeshLocalBlockSize).
492 !% The default is increase_with_dimensions, corresponding to xyz ordering
493 !% in 3D.
494 !%Option increase_with_dimension 1
495 !% The fastest changing index is in the first dimension, i.e., in 3D this
496 !% corresponds to ordering in xyz directions.
497 !%Option decrease_with_dimension 2
498 !% The fastest changing index is in the last dimension, i.e., in 3D this
499 !% corresponds to ordering in zyx directions.
500 !%End
501 call parse_variable(namespace, 'MeshLocalBlockDirection', 1, direction)
502 increase_with_dimension = direction == 1
503 if (direction /= 1 .and. direction /= 2) then
504 call messages_input_error(namespace, 'MeshLocalBlockDirection')
505 end if
506
507 select case (order)
508 case (order_global)
509 ! nothing to do, points are ordered along the global distribution by default
510 case (order_blocks, order_cube)
511 if (order == order_cube) then
512 bsize(1:space%dim) = idx%nr(2, 1:space%dim) - idx%nr(1, 1:space%dim) + 1
513 else
514 !%Variable MeshLocalBlockSize
515 !%Type block
516 !%Section Execution::Optimization
517 !%Description
518 !% To improve memory-access locality when calculating derivatives,
519 !% <tt>Octopus</tt> arranges mesh points in blocks. This variable
520 !% controls the size of this blocks in the different
521 !% directions. The default is selected according to the value of
522 !% the <tt>StatesBlockSize</tt> variable. (This variable only affects the
523 !% performance of <tt>Octopus</tt> and not the results.)
524 !%End
525 if (conf%target_states_block_size < 16) then
526 bsize(1) = 80 * 4 / abs(conf%target_states_block_size)
527 if (space%dim > 1) bsize(2) = 4
528 if (space%dim > 2) bsize(3:) = 10
529 else
530 bsize(1) = max(4 * 16 / abs(conf%target_states_block_size), 1)
531 if (space%dim > 1) bsize(2) = 15
532 if (space%dim > 2) bsize(3:) = 15
533 end if
534
535 if (parse_block(namespace, 'MeshLocalBlockSize', blk) == 0) then
536 nn = parse_block_cols(blk, 0)
537 if (nn /= space%dim) then
538 message(1) = "Error: number of entries in MeshLocalBlockSize must match the umber of dimensions."
539 call messages_fatal(1, namespace=namespace)
540 end if
541 do idir = 1, nn
542 call parse_block_integer(blk, 0, idir - 1, bsize(idir))
543 end do
544 end if
545 end if
546
547 number_of_blocks(1:space%dim) = idx%ll(1:space%dim)/bsize(1:space%dim) + 1
548
549 ! compute new indices locally
550 safe_allocate(reorder_indices(1:pv%np_local))
551 safe_allocate(global_indices(1:pv%np_local))
552 do ip = 1, pv%np_local
553 ipg = pv%local(ip + pv%xlocal - 1)
554 call index_spatial_to_point(idx, space%dim, idx%grid_to_spatial_global(ipg), point)
555 point = point + idx%offset + idx%enlarge
556 reorder_indices(ip) = get_blocked_index(space%dim, point, bsize, number_of_blocks, increase_with_dimension)
557 end do
558 ! sort the local array
559 call sort(reorder_indices, global_indices)
560 safe_deallocate_a(reorder_indices)
561
562 ! reorder according to new order
563 safe_allocate(reordered(1:pv%np_local))
564 do ip = 1, pv%np_local
565 reordered(ip) = pv%local(global_indices(ip) + pv%xlocal - 1)
566 end do
567 safe_deallocate_a(global_indices)
568
569 ! assign the reordered points
570 do ip = 1, pv%np_local
571 pv%local(ip + pv%xlocal - 1) = reordered(ip)
572 end do
573 safe_deallocate_a(reordered)
574
575 ! Recreate hash table.
576 call lihash_end(pv%global)
577 call lihash_init(pv%global)
578 ! Insert local points.
579 do ip = 1, pv%np_local
580 call lihash_insert(pv%global, pv%local(pv%xlocal + ip - 1), ip)
581 end do
582 end select
583
585 end subroutine reorder_points
586
587 subroutine init_mpi_alltoall()
588 integer, allocatable :: part_local(:)
589
591
592 safe_allocate(part_local(1:pv%np_local))
593 safe_allocate(indices(1:pv%np_local))
594 do ip = 1, pv%np_local
595 indices(ip) = pv%xlocal + ip - 1
596 end do
597 call partition_get_partition_number(partition, pv%np_local, &
598 indices, part_local)
599 safe_deallocate_a(indices)
600
601 safe_allocate(pv%send_count(1:npart))
602 safe_allocate(pv%recv_count(1:npart))
603 safe_allocate(pv%send_disp(1:npart))
604 safe_allocate(pv%recv_disp(1:npart))
605
606 pv%send_count = 0
607 do ip = 1, pv%np_local
608 ipart = part_local(ip)
609 pv%send_count(ipart) = pv%send_count(ipart) + 1
610 end do
611 pv%send_disp(1) = 0
612 do ipart = 2, npart
613 pv%send_disp(ipart) = pv%send_disp(ipart - 1) + pv%send_count(ipart - 1)
614 end do
615
616 call pv%mpi_grp%alltoall(pv%send_count, 1, mpi_integer, &
617 pv%recv_count, 1, mpi_integer)
618
619 pv%recv_disp(1) = 0
620 do ipart = 2, npart
621 pv%recv_disp(ipart) = pv%recv_disp(ipart - 1) + pv%recv_count(ipart - 1)
622 end do
623
624 ! create maps
625 safe_allocate(pv%sendmap(1:pv%np_local))
626 safe_allocate(points(1:pv%npart))
627 points = 0
628 do ip = 1, pv%np_local
629 ipart = part_local(ip)
630 points(ipart) = points(ipart) + 1
631 pv%sendmap(ip) = pv%send_disp(ipart) + points(ipart)
632 end do
633 safe_deallocate_a(points)
634
635 safe_allocate(indices(1:pv%np_local))
636 do ip = 1, pv%np_local
637 indices(pv%sendmap(ip)) = pv%xlocal + ip - 1
638 end do
639 safe_allocate(pv%recvmap(1:sum(pv%recv_count)))
640 call pv%mpi_grp%alltoallv(indices, pv%send_count, pv%send_disp, mpi_integer8, &
641 pv%recvmap, pv%recv_count, pv%recv_disp, mpi_integer8)
642 do ip = 1, sum(pv%recv_count)
643 ! get local index
644 index = lihash_lookup(pv%global, pv%recvmap(ip), found)
645 assert(found)
646 pv%recvmap(ip) = index
647 end do
648 safe_deallocate_a(indices)
649
651 end subroutine init_mpi_alltoall
652 end subroutine par_vec_init
653
654 ! ---------------------------------------------------------
656 subroutine par_vec_end(pv)
657 type(par_vec_t), intent(inout) :: pv
658
659 push_sub(par_vec_end)
660
661 safe_deallocate_a(pv%ghost_rdispls)
662 safe_deallocate_a(pv%ghost_sdispls)
663 safe_deallocate_a(pv%ghost_rcounts)
664 safe_deallocate_a(pv%ghost_scounts)
665 safe_deallocate_a(pv%ghost_sendpos)
666 safe_deallocate_a(pv%ghost_recvmap)
667 safe_deallocate_a(pv%ghost_sendmap)
668 safe_deallocate_a(pv%send_disp)
669 safe_deallocate_a(pv%recv_disp)
670 safe_deallocate_a(pv%np_local_vec)
671 safe_deallocate_a(pv%xlocal_vec)
672 safe_deallocate_a(pv%local)
673 safe_deallocate_a(pv%send_count)
674 safe_deallocate_a(pv%recv_count)
675 safe_deallocate_a(pv%sendmap)
676 safe_deallocate_a(pv%recvmap)
677 safe_deallocate_a(pv%bndry)
678 safe_deallocate_a(pv%ghost)
679
680 call lihash_end(pv%global)
681
683 call accel_free_buffer(pv%buff_recvmap)
684 call accel_free_buffer(pv%buff_sendmap)
685 end if
686
687 pop_sub(par_vec_end)
688 end subroutine par_vec_end
689
690
691 ! ---------------------------------------------------------
694 integer function par_vec_global2local(pv, ipg) result(ip)
695 type(par_vec_t), intent(in) :: pv
696 integer(int64), intent(in) :: ipg
697
698 integer :: nn
699 logical :: found
700
701! no push_sub because called too frequently
702
703 if (pv%npart > 1) then
704 ip = 0
705 nn = lihash_lookup(pv%global, ipg, found)
706 if (found) ip = nn
707 else
708 assert(ipg < huge(ip))
709 ip = int(ipg, int32)
710 end if
711 end function par_vec_global2local
712
713 ! ---------------------------------------------------------
715 integer(int64) function par_vec_local2global(pv, ip) result(ipg)
716 type(par_vec_t), intent(in) :: pv
717 integer, intent(in) :: ip
718
719! no push_sub because called too frequently
720
721 if (pv%npart == 1) then
722 ipg = ip
723 else
724 if (ip <= pv%np_local) then
725 ipg = pv%local(pv%xlocal + ip - 1)
726 else if (ip <= pv%np_local + pv%np_ghost) then
727 ipg = pv%ghost(ip - pv%np_local)
728 else if (ip <= pv%np_local + pv%np_ghost + pv%np_bndry) then
729 ipg = pv%bndry(ip - pv%np_local - pv%np_ghost)
730 else
731 ipg = 0_int64
732 end if
733 end if
734 end function par_vec_local2global
735
736 ! gather all local arrays into a global one on rank root
737 ! this gives the global mapping of the index in the partition to the global index
738 subroutine gather_local_vec(pv, root, local_vec)
739 type(par_vec_t), intent(in) :: pv
740 integer, intent(in) :: root
741 integer(int64), allocatable, intent(inout) :: local_vec(:)
742
743 integer(int64), allocatable :: xlocal_tmp(:)
744
745 push_sub(gather_local_vec)
746
747 safe_allocate(xlocal_tmp(1:pv%npart))
748 xlocal_tmp(:) = pv%xlocal_vec(:) - 1
749 ! Gather all the local vectors in a unique big one
750 call pv%mpi_grp%gatherv(pv%local(pv%xlocal:), pv%np_local, mpi_integer8, &
751 local_vec, pv%np_local_vec, xlocal_tmp, mpi_integer8, root)
752 safe_deallocate_a(xlocal_tmp)
753
754 pop_sub(gather_local_vec)
755 end subroutine gather_local_vec
756
757#include "undef.F90"
758#include "complex.F90"
759#include "par_vec_inc.F90"
760
761#include "undef.F90"
762#include "real.F90"
763#include "par_vec_inc.F90"
764
765#include "undef.F90"
766#include "integer.F90"
767#include "par_vec_inc.F90"
768
769#include "undef.F90"
770#include "real32.F90"
771#include "par_vec_inc.F90"
772
773#include "undef.F90"
774#include "complex32.F90"
775#include "par_vec_inc.F90"
776
777end module par_vec_oct_m
778
779!! Local Variables:
780!! mode: f90
781!! coding: utf-8
782!! End:
This is the common interface to a sorting routine. It performs the shell algorithm,...
Definition: sort.F90:156
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:990
pure logical function, public accel_is_enabled()
Definition: accel.F90:414
integer, parameter, public accel_mem_read_only
Definition: accel.F90:185
type(debug_t), save, public debug
Definition: debug.F90:156
type(conf_t), public conf
Global instance of Octopus configuration.
Definition: global.F90:190
This module implements a simple hash table for non-negative integer keys and integer values.
Definition: iihash.F90:127
integer function, public lihash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
Definition: iihash.F90:336
subroutine, public lihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
Definition: iihash.F90:310
subroutine, public lihash_end(h)
Free a hash table.
Definition: iihash.F90:288
subroutine, public lihash_init(h)
Initialize a hash table h.
Definition: iihash.F90:265
This module implements the index, used for the mesh points.
Definition: index.F90:124
integer(int64) function, public get_blocked_index(dim, point, bsize, number_of_blocks, increase_with_dimensions)
Definition: index.F90:499
subroutine, public index_spatial_to_point(idx, dim, ispatial, point)
Definition: index.F90:400
subroutine, public index_to_coords(idx, ip, ix)
Given a global point index, this function returns the set of integer coordinates of the point.
Definition: index.F90:299
integer(int64) function, public index_from_coords(idx, ix)
This function takes care of the boundary conditions for a given vector of integer coordinates it retu...
Definition: index.F90:258
Definition: io.F90:116
subroutine, public io_close(iunit, grp)
Definition: io.F90:467
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:361
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:402
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
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine mpi_grp_copy(mpi_grp_out, mpi_grp_in)
MPI_THREAD_FUNNELED allows for calls to MPI from an OMP region if the thread is the team master.
Definition: mpi.F90:449
Some general things and nomenclature:
Definition: par_vec.F90:173
subroutine cpar_vec_scatter(pv, root, v_local, v)
Generally: Xpar_vec_gather and Xpar_vec_scatter only consider inner points. Xpar_vec_scatter_bndry ta...
Definition: par_vec.F90:1855
subroutine, public par_vec_end(pv)
Deallocate memory used by pv.
Definition: par_vec.F90:752
integer function, public par_vec_global2local(pv, ipg)
Returns local number of global point ip on the local node If the result is zero, the point is not ava...
Definition: par_vec.F90:790
subroutine ipar_vec_scatter(pv, root, v_local, v)
Generally: Xpar_vec_gather and Xpar_vec_scatter only consider inner points. Xpar_vec_scatter_bndry ta...
Definition: par_vec.F90:1389
subroutine dpar_vec_allgather(pv, v, v_local)
Like Xpar_vec_gather but the result is gathered on all nodes, i. e. v has to be a properly allocated ...
Definition: par_vec.F90:1286
subroutine zpar_vec_scatter(pv, root, v_local, v)
Generally: Xpar_vec_gather and Xpar_vec_scatter only consider inner points. Xpar_vec_scatter_bndry ta...
Definition: par_vec.F90:931
subroutine dpar_vec_scatter(pv, root, v_local, v)
Generally: Xpar_vec_gather and Xpar_vec_scatter only consider inner points. Xpar_vec_scatter_bndry ta...
Definition: par_vec.F90:1160
integer(int64) function, public par_vec_local2global(pv, ip)
Returns global index of local point ip.
Definition: par_vec.F90:811
subroutine, public par_vec_init(mpi_grp, np_global, idx, stencil, space, partition, pv, namespace)
Initializes a par_vec_type object (parallel vector).
Definition: par_vec.F90:302
subroutine spar_vec_gather(pv, root, v_local, v)
Reverse operation of Xpar_vec_scatter. All v_locals from the nodes are packed together into v on node...
Definition: par_vec.F90:1685
subroutine ipar_vec_gather(pv, root, v_local, v)
Reverse operation of Xpar_vec_scatter. All v_locals from the nodes are packed together into v on node...
Definition: par_vec.F90:1452
subroutine zpar_vec_gather(pv, root, v_local, v)
Reverse operation of Xpar_vec_scatter. All v_locals from the nodes are packed together into v on node...
Definition: par_vec.F90:994
subroutine spar_vec_allgather(pv, v, v_local)
Like Xpar_vec_gather but the result is gathered on all nodes, i. e. v has to be a properly allocated ...
Definition: par_vec.F90:1748
subroutine gather_local_vec(pv, root, local_vec)
Definition: par_vec.F90:834
subroutine cpar_vec_gather(pv, root, v_local, v)
Reverse operation of Xpar_vec_scatter. All v_locals from the nodes are packed together into v on node...
Definition: par_vec.F90:1918
subroutine dpar_vec_gather(pv, root, v_local, v)
Reverse operation of Xpar_vec_scatter. All v_locals from the nodes are packed together into v on node...
Definition: par_vec.F90:1223
subroutine cpar_vec_allgather(pv, v, v_local)
Like Xpar_vec_gather but the result is gathered on all nodes, i. e. v has to be a properly allocated ...
Definition: par_vec.F90:1981
subroutine zpar_vec_allgather(pv, v, v_local)
Like Xpar_vec_gather but the result is gathered on all nodes, i. e. v has to be a properly allocated ...
Definition: par_vec.F90:1057
subroutine spar_vec_scatter(pv, root, v_local, v)
Generally: Xpar_vec_gather and Xpar_vec_scatter only consider inner points. Xpar_vec_scatter_bndry ta...
Definition: par_vec.F90:1622
subroutine ipar_vec_allgather(pv, v, v_local)
Like Xpar_vec_gather but the result is gathered on all nodes, i. e. v has to be a properly allocated ...
Definition: par_vec.F90:1515
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
subroutine, public partition_get_np_local(partition, np_local_vec)
Given the partition, returns the corresponding number of local points that each partition has.
Definition: partition.F90:564
subroutine, public partition_get_local(partition, rbuffer, np_local)
Calculates the local vector of all partitions in parallel. Local vector stores the global point indic...
Definition: partition.F90:624
This module is intended to contain "only mathematical" functions and procedures.
Definition: sort.F90:119
This module defines stencils used in Octopus.
Definition: stencil.F90:137
type(type_t), parameter, public type_integer
Definition: types.F90:138
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:120
subroutine, public make_array_larger(array, new_size)
Definition: utils.F90:680
subroutine init_mpi_alltoall()
Definition: par_vec.F90:683
subroutine reorder_points()
Definition: par_vec.F90:545
Parallel information.
Definition: par_vec.F90:212
int true(void)