You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
8.4 KiB
Fortran
296 lines
8.4 KiB
Fortran
!
|
|
! Parallel Sparse BLAS version 3.5
|
|
! (C) Copyright 2006-2018
|
|
! Salvatore Filippone
|
|
! Alfredo Buttari
|
|
!
|
|
! Redistribution and use in source and binary forms, with or without
|
|
! modification, are permitted provided that the following conditions
|
|
! are met:
|
|
! 1. Redistributions of source code must retain the above copyright
|
|
! notice, this list of conditions and the following disclaimer.
|
|
! 2. Redistributions in binary form must reproduce the above copyright
|
|
! notice, this list of conditions, and the following disclaimer in the
|
|
! documentation and/or other materials provided with the distribution.
|
|
! 3. The name of the PSBLAS group or the names of its contributors may
|
|
! not be used to endorse or promote products derived from this
|
|
! software without specific written permission.
|
|
!
|
|
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
! ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
! TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
! PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PSBLAS GROUP OR ITS CONTRIBUTORS
|
|
! BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
! POSSIBILITY OF SUCH DAMAGE.
|
|
!
|
|
!
|
|
!
|
|
! Purpose:
|
|
! Provide functions to handle a distribution of a general
|
|
! rectangular 2/3/n-dimensional domain onto
|
|
! a rectangular 2/3/n-dimensional grid of processes
|
|
!
|
|
! See test/pargen/psb_X_pdeNd for examples of usage
|
|
!
|
|
module psb_partidx_mod
|
|
use psb_base_mod, only : psb_ipk_
|
|
|
|
interface idx2ijk
|
|
module procedure idx2ijk3d, idx2ijkv, idx2ijk2d
|
|
end interface idx2ijk
|
|
|
|
interface ijk2idx
|
|
module procedure ijk2idx3d, ijk2idxv, ijk2idx2d
|
|
end interface ijk2idx
|
|
|
|
logical, private, save :: col_major=.true.
|
|
|
|
contains
|
|
|
|
subroutine psb_pidx_set_col_major(val)
|
|
implicit none
|
|
logical, intent(in), optional :: val
|
|
logical :: val_
|
|
val_ =.true.
|
|
if (present(val)) val_ = val
|
|
col_major = val_
|
|
end subroutine psb_pidx_set_col_major
|
|
|
|
subroutine psb_pidx_set_row_major()
|
|
implicit none
|
|
call psb_pidx_set_col_major(.false.)
|
|
end subroutine psb_pidx_set_row_major
|
|
|
|
function psb_pidx_get_col_major() result(val)
|
|
implicit none
|
|
logical :: val
|
|
val = col_major
|
|
end function psb_pidx_get_col_major
|
|
|
|
!
|
|
! Given a global index IDX and the domain size (NX,NY,NZ)
|
|
! compute the point coordinates (I,J,K)
|
|
! Optional argument: base 0 or 1, default 1
|
|
!
|
|
! This mapping is equivalent to a loop nesting:
|
|
! idx = base
|
|
! do i=1,nx
|
|
! do j=1,ny
|
|
! do k=1,nz
|
|
! ijk2idx(i,j,k) = idx
|
|
! idx = idx + 1
|
|
subroutine idx2ijk3d(i,j,k,idx,nx,ny,nz,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: i,j,k
|
|
integer(psb_ipk_), intent(in) :: idx,nx,ny,nz
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
integer(psb_ipk_) :: coords(3)
|
|
|
|
call idx2ijk(coords,idx,[nx,ny,nz],base)
|
|
|
|
k = coords(3)
|
|
j = coords(2)
|
|
i = coords(1)
|
|
|
|
end subroutine idx2ijk3d
|
|
|
|
subroutine idx2ijk2d(i,j,idx,nx,ny,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: i,j
|
|
integer(psb_ipk_), intent(in) :: idx,nx,ny
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
integer(psb_ipk_) :: coords(2)
|
|
|
|
call idx2ijk(coords,idx,[nx,ny],base)
|
|
|
|
j = coords(2)
|
|
i = coords(1)
|
|
|
|
end subroutine idx2ijk2d
|
|
|
|
!
|
|
! Given a global index IDX and the domain size (NX,NY,NZ)
|
|
! compute the point coordinates (I,J,K)
|
|
! Optional argument: base 0 or 1, default 1
|
|
!
|
|
! This mapping is equivalent to a loop nesting:
|
|
! idx = base
|
|
! do i=1,nx
|
|
! do j=1,ny
|
|
! do k=1,nz
|
|
! ijk2idx(i,j,k) = idx
|
|
! idx = idx + 1
|
|
subroutine idx2ijkv(coords,idx,dims,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: coords(:)
|
|
integer(psb_ipk_), intent(in) :: idx,dims(:)
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
integer(psb_ipk_) :: base_, idx_, i, sz
|
|
if (present(base)) then
|
|
base_ = base
|
|
else
|
|
base_ = 1
|
|
end if
|
|
|
|
idx_ = idx - base_
|
|
|
|
if (size(coords) < size(dims)) then
|
|
write(0,*) 'Error: size mismatch ',size(coords),size(dims)
|
|
coords = 0
|
|
return
|
|
end if
|
|
|
|
!
|
|
! This code is equivalent to (3D case)
|
|
! k = mod(idx_,nz) + base_
|
|
! j = mod(idx_/nz,ny) + base_
|
|
! i = mod(idx_/(nx*ny),nx) + base_
|
|
!
|
|
if (col_major) then
|
|
do i=1,size(dims)
|
|
coords(i) = mod(idx_,dims(i)) + base_
|
|
idx_ = idx_ / dims(i)
|
|
end do
|
|
else
|
|
do i=size(dims),1,-1
|
|
coords(i) = mod(idx_,dims(i)) + base_
|
|
idx_ = idx_ / dims(i)
|
|
end do
|
|
end if
|
|
|
|
end subroutine idx2ijkv
|
|
|
|
!
|
|
! Given a triple (I,J,K) and the domain size (NX,NY,NZ)
|
|
! compute the global index IDX
|
|
! Optional argument: base 0 or 1, default 1
|
|
!
|
|
! This mapping is equivalent to a loop nesting:
|
|
! idx = base
|
|
! do i=1,nx
|
|
! do j=1,ny
|
|
! do k=1,nz
|
|
! ijk2idx(i,j,k) = idx
|
|
! idx = idx + 1
|
|
subroutine ijk2idxv(idx,coords,dims,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(in) :: coords(:),dims(:)
|
|
integer(psb_ipk_), intent(out) :: idx
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
integer(psb_ipk_) :: base_, i, sz
|
|
if (present(base)) then
|
|
base_ = base
|
|
else
|
|
base_ = 1
|
|
end if
|
|
sz = size(coords)
|
|
if (sz /= size(dims)) then
|
|
write(0,*) 'Error: size mismatch ',size(coords),size(dims)
|
|
idx = 0
|
|
return
|
|
end if
|
|
|
|
if (col_major) then
|
|
idx = coords(sz) - base_
|
|
do i=sz-1,1,-1
|
|
idx = (idx * dims(i)) + coords(i) - base_
|
|
end do
|
|
idx = idx + base_
|
|
else
|
|
idx = coords(1) - base_
|
|
do i=2,sz
|
|
idx = (idx * dims(i)) + coords(i) - base_
|
|
end do
|
|
idx = idx + base_
|
|
end if
|
|
end subroutine ijk2idxv
|
|
!
|
|
! Given a triple (I,J,K) and the domain size (NX,NY,NZ)
|
|
! compute the global index IDX
|
|
! Optional argument: base 0 or 1, default 1
|
|
!
|
|
! This mapping is equivalent to a loop nesting:
|
|
! idx = base
|
|
! do i=1,nx
|
|
! do j=1,ny
|
|
! do k=1,nz
|
|
! ijk2idx(i,j,k) = idx
|
|
! idx = idx + 1
|
|
subroutine ijk2idx3d(idx,i,j,k,nx,ny,nz,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: idx
|
|
integer(psb_ipk_), intent(in) :: i,j,k,nx,ny,nz
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
! idx = ((i-base_)*nz*ny + (j-base_)*nz + k - base_) + base_
|
|
call ijk2idx(idx,[i,j,k],[nx,ny,nz],base)
|
|
end subroutine ijk2idx3d
|
|
|
|
subroutine ijk2idx2d(idx,i,j,nx,ny,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: idx
|
|
integer(psb_ipk_), intent(in) :: i,j,nx,ny
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
|
|
! idx = ((i-base_)*ny + (j-base_) + base_
|
|
call ijk2idx(idx,[i,j],[nx,ny],base)
|
|
end subroutine ijk2idx2d
|
|
|
|
!
|
|
! dist1Didx
|
|
! Given an index space [base : N-(1-base)] and
|
|
! a set of NP processes, split the index base as
|
|
! evenly as possible, i.e. difference in size
|
|
! between any two processes is either 0 or 1,
|
|
! then return the boundaries in a vector
|
|
! such that
|
|
! V(P) : first index owned by process P
|
|
! V(P+1) : first index owned by process P+1
|
|
!
|
|
subroutine dist1Didx(v,n,np,base)
|
|
use psb_base_mod, only : psb_ipk_
|
|
implicit none
|
|
integer(psb_ipk_), intent(out) :: v(:)
|
|
integer(psb_ipk_), intent(in) :: n, np
|
|
integer(psb_ipk_), intent(in), optional :: base
|
|
!
|
|
integer(psb_ipk_) :: base_, nb, i
|
|
|
|
if (present(base)) then
|
|
base_ = base
|
|
else
|
|
base_ = 1
|
|
end if
|
|
|
|
nb = n/np
|
|
do i=1,mod(n,np)
|
|
v(i) = nb + 1
|
|
end do
|
|
do i=mod(n,np)+1,np
|
|
v(i) = nb
|
|
end do
|
|
v(2:np+1) = v(1:np)
|
|
v(1) = base_
|
|
do i=2,np+1
|
|
v(i) = v(i) + v(i-1)
|
|
end do
|
|
end subroutine dist1Didx
|
|
|
|
end module psb_partidx_mod
|
|
|