21 #include <PB3D_macros.h>
57 module procedure get_ser_var_complex
59 module procedure get_ser_var_real
61 module procedure get_ser_var_int
75 module procedure get_ghost_arr_3d_complex
77 module procedure get_ghost_arr_3d_real
79 module procedure get_ghost_arr_2d_complex
81 module procedure get_ghost_arr_1d_real
89 module procedure broadcast_var_real
91 module procedure broadcast_var_int
93 module procedure broadcast_var_log
95 module procedure broadcast_var_complex_arr
97 module procedure broadcast_var_real_arr
99 module procedure broadcast_var_int_arr
101 module procedure broadcast_var_log_arr
106 integer function get_ser_var_complex(var,ser_var,scatter)
result(ierr)
109 character(*),
parameter :: rout_name =
'get_ser_var'
112 complex(dp),
intent(in) :: var(:)
113 complex(dp),
allocatable,
intent(inout) :: ser_var(:)
114 logical,
intent(in),
optional :: scatter
117 character(len=max_str_ln) :: err_msg
118 integer,
allocatable :: recvcounts(:)
119 integer,
allocatable :: displs(:)
121 logical :: scatter_loc
127 scatter_loc = .false.
128 if (
present(scatter)) scatter_loc = scatter
132 if (
rank.eq.0 .or. scatter_loc)
then
136 allocate(recvcounts(0))
139 if (scatter_loc)
then
140 call mpi_allgather(
size(var),1,mpi_integer,recvcounts,1,&
141 &mpi_integer,mpi_comm_world,ierr)
143 call mpi_gather(
size(var),1,mpi_integer,recvcounts,1,&
144 &mpi_integer,0,mpi_comm_world,ierr)
146 err_msg =
'Failed to gather size of parallel variable'
150 if (
allocated(ser_var))
then
151 if (
size(ser_var).ne.sum(recvcounts))
then
153 write(*,*)
size(ser_var), sum(recvcounts)
154 err_msg =
'ser_var has wrong dimensions'
158 allocate(ser_var(sum(recvcounts)))
162 if (
rank.eq.0 .or. scatter_loc)
then
165 displs(id) = displs(id-1) + recvcounts(id-1)
169 if (scatter_loc)
then
170 call mpi_allgatherv(var,
size(var),mpi_double_complex,ser_var,&
171 &recvcounts,displs,mpi_double_complex,mpi_comm_world,ierr)
173 call mpi_gatherv(var,
size(var),mpi_double_complex,ser_var,&
174 &recvcounts,displs,mpi_double_complex,0,mpi_comm_world,ierr)
176 err_msg =
'Failed to gather parallel variable'
178 end function get_ser_var_complex
180 integer function get_ser_var_real(var,ser_var,scatter)
result(ierr)
183 character(*),
parameter :: rout_name =
'get_ser_var_real'
186 real(dp),
intent(in) :: var(:)
187 real(dp),
allocatable,
intent(inout) :: ser_var(:)
188 logical,
intent(in),
optional :: scatter
191 character(len=max_str_ln) :: err_msg
192 integer,
allocatable :: recvcounts(:)
193 integer,
allocatable :: displs(:)
195 logical :: scatter_loc
201 scatter_loc = .false.
202 if (
present(scatter)) scatter_loc = scatter
206 if (
rank.eq.0 .or. scatter_loc)
then
210 allocate(recvcounts(0))
213 if (scatter_loc)
then
214 call mpi_allgather(
size(var),1,mpi_integer,recvcounts,1,&
215 &mpi_integer,mpi_comm_world,ierr)
217 call mpi_gather(
size(var),1,mpi_integer,recvcounts,1,&
218 &mpi_integer,0,mpi_comm_world,ierr)
220 err_msg =
'Failed to gather size of parallel variable'
224 if (
allocated(ser_var))
then
225 if (
size(ser_var).ne.sum(recvcounts))
then
227 write(*,*)
size(ser_var), sum(recvcounts)
228 err_msg =
'ser_var has wrong dimensions'
232 allocate(ser_var(sum(recvcounts)))
236 if (
rank.eq.0 .or. scatter_loc)
then
239 displs(id) = displs(id-1) + recvcounts(id-1)
243 if (scatter_loc)
then
244 call mpi_allgatherv(var,
size(var),mpi_double_precision,ser_var,&
245 &recvcounts,displs,mpi_double_precision,mpi_comm_world,ierr)
247 call mpi_gatherv(var,
size(var),mpi_double_precision,ser_var,&
248 &recvcounts,displs,mpi_double_precision,0,mpi_comm_world,ierr)
250 err_msg =
'Failed to gather parallel variable'
252 end function get_ser_var_real
254 integer function get_ser_var_int(var,ser_var,scatter)
result(ierr)
257 character(*),
parameter :: rout_name =
'get_ser_var_int'
260 integer,
intent(in) :: var(:)
261 integer,
allocatable,
intent(inout) :: ser_var(:)
262 logical,
intent(in),
optional :: scatter
265 character(len=max_str_ln) :: err_msg
266 integer,
allocatable :: recvcounts(:)
267 integer,
allocatable :: displs(:)
269 logical :: scatter_loc
275 scatter_loc = .false.
276 if (
present(scatter)) scatter_loc = scatter
280 if (
rank.eq.0 .or. scatter_loc)
then
284 allocate(recvcounts(0))
287 if (scatter_loc)
then
288 call mpi_allgather(
size(var),1,mpi_integer,recvcounts,1,&
289 &mpi_integer,mpi_comm_world,ierr)
291 call mpi_gather(
size(var),1,mpi_integer,recvcounts,1,&
292 &mpi_integer,0,mpi_comm_world,ierr)
294 err_msg =
'Failed to gather size of parallel variable'
298 if (
allocated(ser_var))
then
299 if (
size(ser_var).ne.sum(recvcounts))
then
301 write(*,*)
size(ser_var), sum(recvcounts)
302 err_msg =
'ser_var has wrong dimensions'
306 allocate(ser_var(sum(recvcounts)))
310 if (
rank.eq.0 .or. scatter_loc)
then
313 displs(id) = displs(id-1) + recvcounts(id-1)
317 if (scatter_loc)
then
318 call mpi_allgatherv(var,
size(var),mpi_integer,ser_var,&
319 &recvcounts,displs,mpi_integer,mpi_comm_world,ierr)
321 call mpi_gatherv(var,
size(var),mpi_integer,ser_var,&
322 &recvcounts,displs,mpi_integer,0,mpi_comm_world,ierr)
324 err_msg =
'Failed to gather parallel variable'
326 end function get_ser_var_int
332 character(*),
parameter :: rout_name =
'redistribute_var'
335 real(dp),
intent(in) :: var(:)
336 real(dp),
intent(inout) :: dis_var(:)
337 integer,
intent(in) :: lims(2)
338 integer,
intent(in) :: lims_dis(2)
342 integer,
allocatable :: lims_tot(:,:)
343 integer,
allocatable :: lims_dis_tot(:,:)
344 integer,
allocatable :: temp_lim(:)
345 integer,
allocatable :: n_vars(:,:)
346 integer,
allocatable :: nr_sen(:)
347 integer,
allocatable :: nr_rec(:)
348 integer,
allocatable :: id_rec(:)
349 integer,
allocatable :: id_sen(:)
357 allocate(lims_dis_tot(2,
n_procs))
359 ierr =
get_ser_var(lims(id:id),temp_lim,scatter=.true.)
361 lims_tot(id,:) = temp_lim
362 ierr =
get_ser_var(lims_dis(id:id),temp_lim,scatter=.true.)
364 lims_dis_tot(id,:) = temp_lim
376 max_loc = lims_dis_tot(1,jd)
378 if (lims_tot(2,id).ge.max_loc)
then
379 n_vars(jd,id) = min(lims_tot(2,id),lims_dis_tot(2,jd)) - &
381 max_loc = max_loc + n_vars(jd,id)
399 nr_rec(id) = n_vars(
rank+1,id)
400 nr_sen(id) = n_vars(id,
rank+1)
401 id_rec(id) = sum(n_vars(
rank+1,1:id-1))
402 id_sen(id) = sum(n_vars(id,1:
rank)) + lims_dis_tot(1,id) - lims(1)
405 call mpi_alltoallv(var,nr_sen,id_sen,mpi_double_precision,&
406 &dis_var,nr_rec,id_rec,mpi_double_precision,mpi_comm_world,ierr)
421 integer function get_ghost_arr_3d_complex(arr,size_ghost)
result(ierr)
424 character(*),
parameter :: rout_name =
'get_ghost_arr_3D_complex'
427 complex(dp),
intent(inout) :: arr(:,:,:)
428 integer,
intent(in) :: size_ghost
431 integer :: n_modes(2)
433 integer :: istat(mpi_status_size)
439 n_modes = [
size(arr,1),
size(arr,2)]
440 tot_size =
size(arr,3)
445 call mpi_recv(arr(:,:,tot_size-size_ghost+1:tot_size),&
446 &size_ghost*product(n_modes),mpi_double_complex,
rank+1,&
447 &
rank+1,mpi_comm_world,istat,ierr)
448 chckerr(
'Failed to receive')
450 call mpi_send(arr(:,:,1:size_ghost),&
451 &size_ghost*product(n_modes),mpi_double_complex,
rank-1,&
452 &
rank,mpi_comm_world,ierr)
453 chckerr(
'Failed to send')
455 call mpi_sendrecv(arr(:,:,1:size_ghost),&
456 &size_ghost*product(n_modes),mpi_double_complex,
rank-1,&
457 &
rank,arr(:,:,tot_size-size_ghost+1:tot_size),&
458 &size_ghost*product(n_modes),mpi_double_complex,&
459 &
rank+1,
rank+1,mpi_comm_world,istat,ierr)
460 chckerr(
'Failed to send and receive')
463 end function get_ghost_arr_3d_complex
465 integer function get_ghost_arr_3d_real(arr,size_ghost)
result(ierr)
468 character(*),
parameter :: rout_name =
'get_ghost_arr_3D_real'
471 real(dp),
intent(inout) :: arr(:,:,:)
472 integer,
intent(in) :: size_ghost
475 integer :: n_modes(2)
477 integer :: istat(mpi_status_size)
483 n_modes = [
size(arr,1),
size(arr,2)]
484 tot_size =
size(arr,3)
489 call mpi_recv(arr(:,:,tot_size-size_ghost+1:tot_size),&
490 &size_ghost*product(n_modes),mpi_double_precision,&
491 &
rank+1,
rank+1,mpi_comm_world,istat,ierr)
492 chckerr(
'Failed to receive')
494 call mpi_send(arr(:,:,1:size_ghost),&
495 &size_ghost*product(n_modes),mpi_double_precision,&
497 chckerr(
'Failed to send')
499 call mpi_sendrecv(arr(:,:,1:size_ghost),&
500 &size_ghost*product(n_modes),mpi_double_precision,&
502 &
rank,arr(:,:,tot_size-size_ghost+1:tot_size),&
503 &size_ghost*product(n_modes),mpi_double_precision,&
504 &
rank+1,
rank+1,mpi_comm_world,istat,ierr)
505 chckerr(
'Failed to send and receive')
508 end function get_ghost_arr_3d_real
510 integer function get_ghost_arr_2d_complex(arr,size_ghost)
result(ierr)
513 character(*),
parameter :: rout_name =
'get_ghost_arr_2D_complex'
516 complex(dp),
intent(inout) :: arr(:,:)
517 integer,
intent(in) :: size_ghost
522 integer :: istat(mpi_status_size)
528 n_modes =
size(arr,1)
529 tot_size =
size(arr,2)
534 call mpi_recv(arr(:,tot_size-size_ghost+1:tot_size),&
535 &size_ghost*n_modes,mpi_double_complex,
rank+1,&
536 &
rank+1,mpi_comm_world,istat,ierr)
537 chckerr(
'Failed to receive')
539 call mpi_send(arr(:,1:size_ghost),size_ghost*n_modes,&
540 &mpi_double_complex,
rank-1,
rank,mpi_comm_world,&
542 chckerr(
'Failed to send')
544 call mpi_sendrecv(arr(:,1:size_ghost),size_ghost*n_modes,&
546 &arr(:,tot_size-size_ghost+1:tot_size),size_ghost*n_modes,&
547 &mpi_double_complex,
rank+1,
rank+1,mpi_comm_world,&
549 chckerr(
'Failed to send and receive')
552 end function get_ghost_arr_2d_complex
554 integer function get_ghost_arr_1d_real(arr,size_ghost)
result(ierr)
557 character(*),
parameter :: rout_name =
'get_ghost_arr_1D_real'
560 real(dp),
intent(in) :: arr(:)
561 integer,
intent(in) :: size_ghost
565 integer :: istat(mpi_status_size)
576 call mpi_recv(arr(tot_size-size_ghost+1:tot_size),&
577 &size_ghost,mpi_double_precision,
rank+1,&
578 &
rank+1,mpi_comm_world,istat,ierr)
579 chckerr(
'Failed to receive')
581 call mpi_send(arr(1:size_ghost),size_ghost,&
582 &mpi_double_precision,
rank-1,
rank,mpi_comm_world,&
584 chckerr(
'Failed to send')
586 call mpi_sendrecv(arr(1:size_ghost),size_ghost,&
588 &arr(tot_size-size_ghost+1:tot_size),size_ghost,&
589 &mpi_double_precision,
rank+1,
rank+1,&
590 &mpi_comm_world,istat,ierr)
591 chckerr(
'Failed to send and receive')
594 end function get_ghost_arr_1d_real
597 integer function broadcast_var_real(var,source)
result(ierr)
598 character(*),
parameter :: rout_name =
'broadcast_var_real'
601 real(
dp),
intent(in) :: var
602 integer,
intent(in),
optional :: source
605 integer :: source_loc = 0
611 if (
present(source)) source_loc = source
613 call mpi_bcast(var,1,mpi_double_precision,source_loc,mpi_comm_world,&
615 chckerr(
'MPI broadcast failed')
616 end function broadcast_var_real
618 integer function broadcast_var_int(var,source)
result(ierr)
619 character(*),
parameter :: rout_name =
'broadcast_var_int'
622 integer,
intent(in) :: var
623 integer,
intent(in),
optional :: source
626 integer :: source_loc = 0
632 if (
present(source)) source_loc = source
634 call mpi_bcast(var,1,mpi_integer,source_loc,mpi_comm_world,ierr)
635 chckerr(
'MPI broadcast failed')
636 end function broadcast_var_int
638 integer function broadcast_var_log(var,source)
result(ierr)
639 character(*),
parameter :: rout_name =
'broadcast_var_log'
642 logical,
intent(in) :: var
643 integer,
intent(in),
optional :: source
646 integer :: source_loc = 0
652 if (
present(source)) source_loc = source
654 call mpi_bcast(var,1,mpi_logical,source_loc,mpi_comm_world,ierr)
655 chckerr(
'MPI broadcast failed')
656 end function broadcast_var_log
658 integer function broadcast_var_complex_arr(var,source)
result(ierr)
659 character(*),
parameter :: rout_name =
'broadcast_var_complex_arr'
662 complex(dp),
intent(in) :: var(:)
663 integer,
intent(in),
optional :: source
666 integer :: source_loc = 0
672 if (
present(source)) source_loc = source
674 call mpi_bcast(var,
size(var),mpi_double_complex,source_loc,&
675 &mpi_comm_world,ierr)
676 chckerr(
'MPI broadcast failed')
677 end function broadcast_var_complex_arr
679 integer function broadcast_var_real_arr(var,source)
result(ierr)
680 character(*),
parameter :: rout_name =
'broadcast_var_real_arr'
683 real(
dp),
intent(in) :: var(:)
684 integer,
intent(in),
optional :: source
687 integer :: source_loc = 0
693 if (
present(source)) source_loc = source
695 call mpi_bcast(var,
size(var),mpi_double_precision,source_loc,&
696 &mpi_comm_world,ierr)
697 chckerr(
'MPI broadcast failed')
698 end function broadcast_var_real_arr
700 integer function broadcast_var_int_arr(var,source)
result(ierr)
701 character(*),
parameter :: rout_name =
'broadcast_var_int_arr'
704 integer,
intent(in) :: var(:)
705 integer,
intent(in),
optional :: source
708 integer :: source_loc = 0
714 if (
present(source)) source_loc = source
716 call mpi_bcast(var,
size(var),mpi_integer,source_loc,mpi_comm_world,ierr)
717 chckerr(
'MPI broadcast failed')
718 end function broadcast_var_int_arr
720 integer function broadcast_var_log_arr(var,source)
result(ierr)
721 character(*),
parameter :: rout_name =
'broadcast_var_log_arr'
724 logical,
intent(in) :: var(:)
725 integer,
intent(in),
optional :: source
728 integer :: source_loc = 0
734 if (
present(source)) source_loc = source
736 call mpi_bcast(var,
size(var),mpi_logical,source_loc,mpi_comm_world,ierr)
737 chckerr(
'MPI broadcast failed')
738 end function broadcast_var_log_arr
743 integer function wait_mpi()
result(ierr)
744 character(*),
parameter :: rout_name =
'wait_MPI'
750 call mpi_barrier(mpi_comm_world,ierr)
751 chckerr(
'MPI Barrier failed')
764 integer function lock_req_acc(lock,blocking)
result(ierr)
768 character(*),
parameter :: rout_name =
'lock_req_acc'
775 integer,
allocatable :: wl_loc(:)
776 integer,
allocatable :: next_nb_procs(:)
777 integer,
allocatable :: ranks_to_activate(:)
778 logical,
intent(in),
optional :: blocking
779 logical :: next_nb_proc_exists
780 logical :: direct_receipt
790 if (.not.
allocated(lock%wl))
then
792 chckerr(
'lock not intialized')
797 lock%blocking = .true.
798 if (
present(blocking)) lock%blocking = blocking
810 direct_receipt =
wl_empty(wl_loc,[-2,-1,1,2])
813 if (direct_receipt)
then
816 &
'and got it right away'
820 next_nb_proc_exists = .false.
821 if (.not.lock%blocking)
then
823 next_nb_proc_exists = &
824 &.not.
wl_empty(wl_loc,[-1],next_procs=next_nb_procs)
828 &
' NB proc, next NB procs found:', next_nb_procs
833 if (.not.lock%blocking .and. next_nb_proc_exists)
then
834 allocate(ranks_to_activate(
size(next_nb_procs)+1))
835 ranks_to_activate = [
rank,next_nb_procs]
837 allocate(ranks_to_activate(1))
838 ranks_to_activate =
rank
845 &
' setting status to activate:', ranks_to_activate
847 ierr =
lock_wl_change(2,.false.,lock,wl_loc,ranks=ranks_to_activate)
851 if (next_nb_proc_exists)
then
852 do id = 1,
size(next_nb_procs)
874 character(*),
parameter :: rout_name =
'lock_return_acc'
881 integer,
allocatable :: wl_loc(:)
882 integer,
allocatable :: next_procs(:)
883 integer,
allocatable :: ranks_to_activate(:)
884 logical :: next_proc_exists
885 logical :: next_proc_bl
894 if (.not.
allocated(lock%wl))
then
896 chckerr(
'lock not intialized')
910 next_proc_bl = .false.
911 next_proc_exists = .false.
912 if (lock%blocking .or.
wl_empty(wl_loc,[-2]))
then
914 next_proc_exists = .not.
wl_empty(wl_loc,[1],next_procs=next_procs)
915 if (next_proc_exists) next_proc_bl = .true.
918 &
' next BL procs found:', next_procs
922 if (.not. next_proc_exists)
then
923 next_proc_exists = .not.
wl_empty(wl_loc,[-1],&
924 &next_procs=next_procs)
925 if (next_proc_exists) next_proc_bl = .false.
929 &
' next NB procs found:', next_procs
935 &
'but has no notification rights'
939 if (next_proc_exists)
then
941 if (next_proc_bl)
then
942 allocate(ranks_to_activate(1))
943 ranks_to_activate = next_procs(1)
945 allocate(ranks_to_activate(
size(next_procs)))
946 ranks_to_activate = next_procs
953 &
' setting status to activate:', ranks_to_activate
956 &ranks=ranks_to_activate)
960 if (next_proc_exists)
then
961 do id = 1,
size(ranks_to_activate)
984 logical function wl_empty(wl,proc_type,next_procs)
988 integer,
intent(in) :: wl(:)
989 integer,
intent(in) :: proc_type(:)
990 integer,
intent(inout),
optional,
allocatable :: next_procs(:)
995 integer,
allocatable :: next_procs_loc(:)
1000 allocate(next_procs_loc(
n_procs))
1007 proc_types:
do jd = 1,
size(proc_type)
1008 if (wl(next_procs_loc(nr_np+1)+1).eq.proc_type(jd))
then
1016 if (.not.
wl_empty .and.
present(next_procs))
then
1017 if (
allocated(next_procs))
deallocate(next_procs)
1018 allocate(next_procs(nr_np))
1019 next_procs = next_procs_loc(1:nr_np)
1030 integer function lock_notify(lock_loc,rec_rank)
result(ierr)
1033 character(*),
parameter :: rout_name =
'lock_notify'
1037 integer,
intent(in) :: rec_rank
1047 call mpi_send(
rank+1,1,mpi_integer,rec_rank,lock_loc%wu_tag,&
1048 &mpi_comm_world,ierr)
1049 chckerr(
'Failed to send notification')
1053 &
' notified', rec_rank
1063 character(*),
parameter :: rout_name =
'lock_get_notified'
1079 &
' but needs to wait for lock'
1081 call mpi_recv(dum_buf,1,mpi_integer,mpi_any_source,&
1082 &lock_loc%wu_tag,mpi_comm_world,mpi_status_ignore,ierr)
1083 chckerr(
'Failed to receive notification')
1086 &
' got notified by ',dum_buf-1
1109 integer function lock_wl_change(wl_action,blocking,lock_loc,wl,ranks) &
1113 character(*),
parameter :: rout_name =
'lock_wl_change'
1116 integer,
intent(in) :: wl_action
1117 logical,
intent(in) :: blocking
1118 type(
lock_type),
intent(inout) :: lock_loc
1119 integer,
intent(inout),
allocatable :: wl(:)
1120 integer,
intent(in),
optional :: ranks(:)
1126 integer,
allocatable :: ranks_loc(:)
1127 integer(kind=MPI_ADDRESS_KIND) :: one = 1
1128 integer(kind=MPI_ADDRESS_KIND) :: disp
1132 integer(kind=8) :: window_time(2)
1140 if (.not.blocking) put_val = -put_val
1142 if (
allocated(wl))
deallocate(wl)
1146 if (.not.
present(ranks))
then
1147 allocate(ranks_loc(1))
1150 allocate(ranks_loc(
size(ranks)))
1153 n_ranks =
size(ranks_loc)
1157 if (
debug_lock)
call system_clock(window_time(1))
1159 call mpi_win_lock(mpi_lock_exclusive,0,0,lock_loc%wl_win,ierr)
1160 chckerr(
'Failed to lock window')
1173 disp = disp + ln + 1
1174 if (id.lt.n_ranks+1)
then
1175 ln = ranks_loc(id)-ranks_loc(id-1)-1
1177 ln =
n_procs-ranks_loc(id-1)-1
1183 call mpi_get(wl(int(disp)+1:int(disp)+ln),ln,mpi_integer,0,&
1184 &disp,ln,mpi_integer,lock_loc%wl_win,ierr)
1185 chckerr(
'Failed to get waiting list')
1189 if (id.lt.n_ranks+1)
then
1190 call mpi_put(put_val,1,mpi_integer,0,ranks_loc(id)*one,1,&
1191 &mpi_integer,lock_loc%wl_win,ierr)
1192 chckerr(
'Failed to add to waiting list')
1193 wl(ranks_loc(id)+1) = put_val
1198 call mpi_win_unlock(0,lock_loc%wl_win,ierr)
1199 chckerr(
'Failed to lock window')
1201 if (
debug_lock)
call system_clock(window_time(2))
1207 &trim(
r2strt(1.e-9_dp*(window_time(2)-window_time(1)))),&
1208 &
' waiting list:', wl
1216 character(len=max_str_ln) function lock_header(lock_loc)
result(header)
1223 integer(kind=8) :: clock
1224 character(len=2) :: block_char
1227 call system_clock(clock)
1230 if (lock_loc%blocking)
then
1236 header = trim(
ii2str(clock))//
' '//trim(
i2str(lock_loc%wu_tag))//
' '//&
1237 &block_char//
' '//trim(
i2str(
rank))//
'-'