diff --git a/Changelog b/Changelog index 0e5380696..7cfc2997a 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,21 @@ Changelog. A lot less detailed than usual, at least for past history. +2019/12/18: New internals and algorithms for FND_OWNER, faster and less + memory hungry. +2019/07/20: New SCAN collective; improve handling of SYMmetric +2019/07/08: Fix memory usage in conversions to/from coo +2019/07/01: Timer facility +2019/06/25: Fix memory footprint in spspmm and other borderline cases +2019/06/17: Make ADD default assembly action. +2019/05/30: new insertion routines in CSR mode +2019/05/27: Fix matrix generation. +2019/05/26: New timer facility (undocumented). +2019/05/20: Change checks on vectors +2019/05/05: Reworked linmap internals +2019/04/15: Improved sphalo and test programs printout +2019/04/09: bump version to 3.6.1 +2019/04/09: new fnd_owner_halo method +2019/03/31: New RENUM_BLK descriptor method 2019/01/16: In bldext, implement ALL_TO_ALLV by hand for certain compilers. 2018/10/10: New ICTXT argument in prec%init diff --git a/Makefile b/Makefile index 829d4fc17..41caa3cdc 100644 --- a/Makefile +++ b/Makefile @@ -15,15 +15,15 @@ libd: (if test ! -d include ; then mkdir include; fi; $(INSTALL_DATA) Make.inc include/Make.inc.psblas) (if test ! -d modules ; then mkdir modules; fi;) based: - cd base && $(MAKE) lib + $(MAKE) -C base lib precd: - cd prec && $(MAKE) lib + $(MAKE) -C prec lib kryld: - cd krylov && $(MAKE) lib + $(MAKE) -C krylov lib utild: - cd util&& $(MAKE) lib + $(MAKE) -C util lib cbindd: - cd cbind&& $(MAKE) lib + $(MAKE) -C cbind lib install: all mkdir -p $(INSTALL_INCLUDEDIR) &&\ @@ -42,11 +42,11 @@ install: all /bin/cp -fr test/pargen test/fileread test/kernel $(INSTALL_SAMPLESDIR) && \ mkdir -p $(INSTALL_SAMPLESDIR)/cbind && /bin/cp -fr cbind/test/pargen/* $(INSTALL_SAMPLESDIR)/cbind clean: - cd base && $(MAKE) clean - cd prec && $(MAKE) clean - cd krylov && $(MAKE) clean - cd util && $(MAKE) clean - cd cbind && $(MAKE) clean + $(MAKE) -C base clean + $(MAKE) -C prec clean + $(MAKE) -C krylov clean + $(MAKE) -C util clean + $(MAKE) -C cbind clean check: all make check -C test/serial diff --git a/base/Makefile b/base/Makefile index 3304176c9..039a59637 100644 --- a/base/Makefile +++ b/base/Makefile @@ -13,25 +13,25 @@ lib: mods sr cm in pb tl sr cm in pb tl: mods mods: - cd modules && $(MAKE) lib LIBNAME=$(BASELIBNAME) F90="$(MPF90)" F90COPT="$(F90COPT) $(MPI_OPT)" + $(MAKE) -C modules lib LIBNAME=$(BASELIBNAME) F90="$(MPF90)" F90COPT="$(F90COPT) $(MPI_OPT)" sr: - cd serial && $(MAKE) lib LIBNAME=$(BASELIBNAME) + $(MAKE) -C serial lib LIBNAME=$(BASELIBNAME) cm: - cd comm && $(MAKE) lib LIBNAME=$(BASELIBNAME) + $(MAKE) -C comm lib LIBNAME=$(BASELIBNAME) in: - cd internals && $(MAKE) lib LIBNAME=$(BASELIBNAME) + $(MAKE) -C internals lib LIBNAME=$(BASELIBNAME) pb: - cd psblas && $(MAKE) lib LIBNAME=$(BASELIBNAME) + $(MAKE) -C psblas lib LIBNAME=$(BASELIBNAME) tl: - cd tools && $(MAKE) lib LIBNAME=$(BASELIBNAME) + $(MAKE) -C tools lib LIBNAME=$(BASELIBNAME) clean: - (cd modules; $(MAKE) clean) - (cd comm; $(MAKE) clean) - (cd internals; $(MAKE) clean) - (cd tools; $(MAKE) clean) - (cd serial; $(MAKE) clean) - (cd psblas; $(MAKE) clean) + ($(MAKE) -C modules clean) + ($(MAKE) -C comm clean) + ($(MAKE) -C internals clean) + ($(MAKE) -C tools clean) + ($(MAKE) -C serial clean) + ($(MAKE) -C psblas clean) veryclean: clean /bin/rm -f $(HERE)/$(LIBNAME) $(LIBMOD) *$(.mod) diff --git a/base/comm/Makefile b/base/comm/Makefile index f27d38cfc..950a95a04 100644 --- a/base/comm/Makefile +++ b/base/comm/Makefile @@ -32,7 +32,7 @@ lib: interns mpfobjs $(OBJS) $(RANLIB) $(LIBDIR)/$(LIBNAME) interns: - cd internals && $(MAKE) lib + $(MAKE) -C internals lib mpfobjs: $(MAKE) $(MPFOBJS) FC="$(MPFC)" diff --git a/base/comm/internals/psi_i2ovrl_restr_a.f90 b/base/comm/internals/psi_i2ovrl_restr_a.f90 new file mode 100644 index 000000000..36bc25661 --- /dev/null +++ b/base/comm/internals/psi_i2ovrl_restr_a.f90 @@ -0,0 +1,129 @@ +! +! 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. +! +! +! Subroutine: psi_i2ovrl_restr +! These subroutines restore the overlap region of a vector; they are used +! for the transpose matrix-vector product when there is a nonempty overlap. +! +! +subroutine psi_i2ovrl_restrr1(x,xs,desc_a,info) + use psi_mod, psi_protect_name => psi_i2ovrl_restrr1 + + implicit none + + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_i2pk_) :: xs(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, isz + character(len=20) :: name, ch_err + + name='psi_i2ovrl_restrr1' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + isz = size(desc_a%ovrlap_elem,1) + + do i=1, isz + idx = desc_a%ovrlap_elem(i,1) + x(idx) = xs(i) + end do + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_restrr1 + +subroutine psi_i2ovrl_restrr2(x,xs,desc_a,info) + use psi_mod, psi_protect_name => psi_i2ovrl_restrr2 + + implicit none + + integer(psb_i2pk_), intent(inout) :: x(:,:) + integer(psb_i2pk_) :: xs(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, isz + character(len=20) :: name, ch_err + + name='psi_i2ovrl_restrr2' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (size(x,2) /= size(xs,2)) then + info = psb_err_internal_error_ + call psb_errpush(info,name, a_err='Mismacth columns X vs XS') + goto 9999 + endif + + + isz = size(desc_a%ovrlap_elem,1) + + do i=1, isz + idx = desc_a%ovrlap_elem(i,1) + x(idx,:) = xs(i,:) + end do + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_restrr2 + diff --git a/base/comm/internals/psi_i2ovrl_save_a.f90 b/base/comm/internals/psi_i2ovrl_save_a.f90 new file mode 100644 index 000000000..55e9ae893 --- /dev/null +++ b/base/comm/internals/psi_i2ovrl_save_a.f90 @@ -0,0 +1,139 @@ +! +! 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. +! +! +! +! Subroutine: psi_i2ovrl_save +! These subroutines save the overlap region of a vector; they are used +! for the transpose matrix-vector product when there is a nonempty overlap. +! +subroutine psi_i2ovrl_saver1(x,xs,desc_a,info) + use psi_mod, psi_protect_name => psi_i2ovrl_saver1 + + use psb_realloc_mod + + implicit none + + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_i2pk_), allocatable :: xs(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, isz + character(len=20) :: name, ch_err + + name='psi_i2ovrl_saver1' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + isz = size(desc_a%ovrlap_elem,1) + call psb_realloc(isz,xs,info) + if (info /= psb_success_) then + info = psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + endif + + do i=1, isz + idx = desc_a%ovrlap_elem(i,1) + xs(i) = x(idx) + end do + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_saver1 + + +subroutine psi_i2ovrl_saver2(x,xs,desc_a,info) + use psi_mod, psi_protect_name => psi_i2ovrl_saver2 + + use psb_realloc_mod + + implicit none + + integer(psb_i2pk_), intent(inout) :: x(:,:) + integer(psb_i2pk_), allocatable :: xs(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, isz, nc + character(len=20) :: name, ch_err + + name='psi_i2ovrl_saver2' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + isz = size(desc_a%ovrlap_elem,1) + nc = size(x,2) + call psb_realloc(isz,nc,xs,info) + if (info /= psb_success_) then + info = psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + endif + + do i=1, isz + idx = desc_a%ovrlap_elem(i,1) + xs(i,:) = x(idx,:) + end do + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_saver2 diff --git a/base/comm/internals/psi_i2ovrl_upd_a.f90 b/base/comm/internals/psi_i2ovrl_upd_a.f90 new file mode 100644 index 000000000..c41803ef3 --- /dev/null +++ b/base/comm/internals/psi_i2ovrl_upd_a.f90 @@ -0,0 +1,173 @@ +! +! 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. +! +! +! Subroutine: psi_i2ovrl_update +! These subroutines update the overlap region of a vector; they are used +! for the transpose matrix-vector product when there is a nonempty overlap, +! or for the application of Additive Schwarz preconditioners. +! +! +subroutine psi_i2ovrl_updr1(x,desc_a,update,info) + use psi_mod, psi_protect_name => psi_i2ovrl_updr1 + + implicit none + + integer(psb_i2pk_), intent(inout), target :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(in) :: update + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, ndm + integer(psb_ipk_) :: ierr(5) + character(len=20) :: name, ch_err + + name='psi_i2ovrl_updr1' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ! switch on update type + select case (update) + case(psb_square_root_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + ndm = desc_a%ovrlap_elem(i,2) + x(idx) = x(idx)/sqrt(real(ndm)) + end do + case(psb_avg_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + ndm = desc_a%ovrlap_elem(i,2) + x(idx) = x(idx)/real(ndm) + end do + case(psb_setzero_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + if (me /= desc_a%ovrlap_elem(i,3))& + & x(idx) = i2zero + end do + case(psb_sum_) + ! do nothing + + case default + ! wrong value for choice argument + info = psb_err_iarg_invalid_value_ + ierr(1) = 3; ierr(2)=update; + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end select + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_updr1 + + +subroutine psi_i2ovrl_updr2(x,desc_a,update,info) + use psi_mod, psi_protect_name => psi_i2ovrl_updr2 + + implicit none + + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(in) :: update + integer(psb_ipk_), intent(out) :: info + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, i, idx, ndm + integer(psb_ipk_) :: ierr(5) + character(len=20) :: name, ch_err + + name='psi_i2ovrl_updr2' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt = desc_a%get_context() + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ! switch on update type + select case (update) + case(psb_square_root_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + ndm = desc_a%ovrlap_elem(i,2) + x(idx,:) = x(idx,:)/sqrt(real(ndm)) + end do + case(psb_avg_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + ndm = desc_a%ovrlap_elem(i,2) + x(idx,:) = x(idx,:)/real(ndm) + end do + case(psb_setzero_) + do i=1,size(desc_a%ovrlap_elem,1) + idx = desc_a%ovrlap_elem(i,1) + if (me /= desc_a%ovrlap_elem(i,3))& + & x(idx,:) = i2zero + end do + case(psb_sum_) + ! do nothing + + case default + ! wrong value for choice argument + info = psb_err_iarg_invalid_value_ + ierr(1) = 3; ierr(2)=update; + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end select + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2ovrl_updr2 diff --git a/base/comm/internals/psi_i2swapdata_a.F90 b/base/comm/internals/psi_i2swapdata_a.F90 new file mode 100644 index 000000000..479042c4f --- /dev/null +++ b/base/comm/internals/psi_i2swapdata_a.F90 @@ -0,0 +1,990 @@ +! +! 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. +! +! +! +! File: psi_i2swapdata.F90 +! +! Subroutine: psi_i2swapdatam +! Implements the data exchange among processes. Essentially this is doing +! a variable all-to-all data exchange (ALLTOALLV in MPI parlance), but +! it is capable of pruning empty exchanges, which are very likely in our +! application environment. All the variants have the same structure +! In all these subroutines X may be: I Integer +! S real(psb_spk_) +! D real(psb_dpk_) +! C complex(psb_spk_) +! Z complex(psb_dpk_) +! Basically the operation is as follows: on each process, we identify +! sections SND(Y) and RCV(Y); then we do a send on (PACK(SND(Y))); +! then we receive, and we do an update with Y = UNPACK(RCV(Y)) + BETA * Y +! but only on the elements involved in the UNPACK operation. +! Thus: for halo data exchange, the receive section is confined in the +! halo indices, and BETA=0, whereas for overlap exchange the receive section +! is scattered in the owned indices, and BETA=1. +! The first routine picks the desired exchange index list and passes it to the second. +! +! Arguments: +! flag - integer Choose the algorithm for data exchange: +! this is chosen through bit fields. +! swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! swap_sync = iand(flag,psb_swap_sync_) /= 0 +! swap_send = iand(flag,psb_swap_send_) /= 0 +! swap_recv = iand(flag,psb_swap_recv_) /= 0 +! if (swap_mpi): use underlying MPI_ALLTOALLV. +! if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +! n - integer Number of columns in Y +! beta - integer Choose overwrite or sum. +! y(:,:) - integer The data area +! desc_a - type(psb_desc_type). The communication descriptor. +! work(:) - integer Buffer space. If not sufficient, will do +! our own internal allocation. +! info - integer. return code. +! data - integer which list is to be used to exchange data +! default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psi_i2swapdatam(flag,n,beta,y,desc_a,work,info,data) + + use psi_mod, psb_protect_name => psi_i2swapdatam + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_), target :: work(:) + type(psb_desc_type),target :: desc_a + integer(psb_ipk_), optional :: data + + ! locals + integer(psb_ipk_) :: ictxt, np, me, icomm, idxs, idxr, totxch, data_, err_act + integer(psb_ipk_), pointer :: d_idx(:) + character(len=20) :: name + + info=psb_success_ + name='psi_swap_data' + call psb_erractionsave(err_act) + + ictxt = desc_a%get_context() + icomm = desc_a%get_mpic() + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (.not.psb_is_asb_desc(desc_a)) then + info=psb_err_invalid_cd_state_ + call psb_errpush(info,name) + goto 9999 + endif + + if(present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + end if + + call desc_a%get_list(data_,d_idx,totxch,idxr,idxs,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='psb_cd_get_list') + goto 9999 + end if + + call psi_swapdata(ictxt,icomm,flag,n,beta,y,d_idx,totxch,idxs,idxr,work,info) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2swapdatam + +subroutine psi_i2swapidxm(iictxt,iicomm,flag,n,beta,y,idx, & + & totxch,totsnd,totrcv,work,info) + + use psi_mod, psb_protect_name => psi_i2swapidxm + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: iictxt,iicomm,flag,n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_), target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd, totrcv + + ! locals + integer(psb_mpk_) :: ictxt, icomm, np, me,& + & proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret + integer(psb_mpk_), allocatable, dimension(:) :: bsdidx, brvidx,& + & sdsz, rvsz, prcid, rvhd, sdhd + integer(psb_ipk_) :: nesd, nerv,& + & err_act, i, idx_pt, totsnd_, totrcv_,& + & snd_pt, rcv_pt, pnti + logical :: swap_mpi, swap_sync, swap_send, swap_recv,& + & albf,do_send,do_recv + logical, parameter :: usersend=.false. + + integer(psb_i2pk_), pointer, dimension(:) :: sndbuf, rcvbuf +#ifdef HAVE_VOLATILE + volatile :: sndbuf, rcvbuf +#endif + character(len=20) :: name + + info=psb_success_ + name='psi_swap_data' + call psb_erractionsave(err_act) + ictxt = iictxt + icomm = iicomm + + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + swap_mpi = iand(flag,psb_swap_mpi_) /= 0 + swap_sync = iand(flag,psb_swap_sync_) /= 0 + swap_send = iand(flag,psb_swap_send_) /= 0 + swap_recv = iand(flag,psb_swap_recv_) /= 0 + + do_send = swap_mpi .or. swap_sync .or. swap_send + do_recv = swap_mpi .or. swap_sync .or. swap_recv + + totrcv_ = totrcv * n + totsnd_ = totsnd * n + + if (swap_mpi) then + allocate(sdsz(0:np-1), rvsz(0:np-1), bsdidx(0:np-1),& + & brvidx(0:np-1), rvhd(0:np-1), sdhd(0:np-1), prcid(0:np-1),& + & stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + rvhd(:) = mpi_request_null + sdsz(:) = 0 + rvsz(:) = 0 + + ! prepare info for communications + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(proc_to_comm) = psb_get_mpi_rank(ictxt,proc_to_comm) + + brvidx(proc_to_comm) = rcv_pt + rvsz(proc_to_comm) = n*nerv + + bsdidx(proc_to_comm) = snd_pt + sdsz(proc_to_comm) = n*nesd + + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + else + allocate(rvhd(totxch),prcid(totxch),stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + end if + + totrcv_ = max(totrcv_,1) + totsnd_ = max(totsnd_,1) + if((totrcv_+totsnd_) < size(work)) then + sndbuf => work(1:totsnd_) + rcvbuf => work(totsnd_+1:totsnd_+totrcv_) + albf=.false. + else + allocate(sndbuf(totsnd_),rcvbuf(totrcv_), stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + albf=.true. + end if + + if (do_send) then + + ! Pack send buffers + pnti = 1 + snd_pt = 1 + do i=1, totxch + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+nerv+psb_n_elem_send_ + call psi_gth(nesd,n,idx(idx_pt:idx_pt+nesd-1),& + & y,sndbuf(snd_pt:snd_pt+n*nesd-1)) + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + + + ! Case SWAP_MPI + if (swap_mpi) then + + ! swap elements using mpi_alltoallv + call mpi_alltoallv(sndbuf,sdsz,bsdidx,& + & psb_mpi_i2pk_,rcvbuf,rvsz,& + & brvidx,psb_mpi_i2pk_,icomm,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + + else if (swap_sync) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if (proc_to_comm < me) then + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + else if (proc_to_comm > me) then + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swapdata: mismatch on self send',& + & nerv,nesd + end if + rcvbuf(rcv_pt:rcv_pt+n*nerv-1) = sndbuf(snd_pt:snd_pt+n*nesd-1) + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + + else if (swap_send .and. swap_recv) then + + ! First I post all the non blocking receives + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(i) = psb_get_mpi_rank(ictxt,proc_to_comm) + if ((nerv>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + call mpi_irecv(rcvbuf(rcv_pt),n*nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag, icomm,rvhd(i),iret) + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + + ! Then I post all the blocking sends + if (usersend) call mpi_barrier(icomm,iret) + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + p2ptag = psb_int2_swap_tag + if ((nesd>0).and.(proc_to_comm /= me)) then + if (usersend) then + call mpi_rsend(sndbuf(snd_pt),n*nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + else + call mpi_send(sndbuf(snd_pt),n*nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + end if + + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + + pnti = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + p2ptag = psb_int2_swap_tag + + if ((proc_to_comm /= me).and.(nerv>0)) then + call mpi_wait(rvhd(i),p2pstat,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*)& + & 'Fatal error in swapdata: mismatch on self send', & + & nerv,nesd + end if + rcvbuf(rcv_pt:rcv_pt+n*nerv-1) = sndbuf(snd_pt:snd_pt+n*nesd-1) + end if + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + else if (swap_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (do_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+psb_n_elem_recv_ + call psi_sct(nerv,n,idx(idx_pt:idx_pt+nerv-1),& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1),beta,y) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + + if (swap_mpi) then + deallocate(sdsz,rvsz,bsdidx,brvidx,rvhd,prcid,sdhd,& + & stat=info) + else + deallocate(rvhd,prcid,stat=info) + end if + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + if(albf) deallocate(sndbuf,rcvbuf,stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(iictxt,err_act) + + return +end subroutine psi_i2swapidxm + +! +! +! Subroutine: psi_i2swapdatav +! Implements the data exchange among processes. Essentially this is doing +! a variable all-to-all data exchange (ALLTOALLV in MPI parlance), but +! it is capable of pruning empty exchanges, which are very likely in out +! application environment. All the variants have the same structure +! In all these subroutines X may be: I Integer +! S real(psb_spk_) +! D real(psb_dpk_) +! C complex(psb_spk_) +! Z complex(psb_dpk_) +! Basically the operation is as follows: on each process, we identify +! sections SND(Y) and RCV(Y); then we do a SEND(PACK(SND(Y))); +! then we receive, and we do an update with Y = UNPACK(RCV(Y)) + BETA * Y +! but only on the elements involved in the UNPACK operation. +! Thus: for halo data exchange, the receive section is confined in the +! halo indices, and BETA=0, whereas for overlap exchange the receive section +! is scattered in the owned indices, and BETA=1. +! The first routine picks the desired exchange index list and passes it to the second. +! +! Arguments: +! flag - integer Choose the algorithm for data exchange: +! this is chosen through bit fields. +! swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! swap_sync = iand(flag,psb_swap_sync_) /= 0 +! swap_send = iand(flag,psb_swap_send_) /= 0 +! swap_recv = iand(flag,psb_swap_recv_) /= 0 +! if (swap_mpi): use underlying MPI_ALLTOALLV. +! if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +! n - integer Number of columns in Y +! beta - integer Choose overwrite or sum. +! y(:) - integer The data area +! desc_a - type(psb_desc_type). The communication descriptor. +! work(:) - integer Buffer space. If not sufficient, will do +! our own internal allocation. +! info - integer. return code. +! data - integer which list is to be used to exchange data +! default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psi_i2swapdatav(flag,beta,y,desc_a,work,info,data) + + use psi_mod, psb_protect_name => psi_i2swapdatav + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_), target :: work(:) + type(psb_desc_type),target :: desc_a + integer(psb_ipk_), optional :: data + + ! locals + integer(psb_ipk_) :: ictxt, np, me, icomm, idxs, idxr, totxch, data_, err_act + integer(psb_ipk_), pointer :: d_idx(:) + character(len=20) :: name + + info=psb_success_ + name='psi_swap_datav' + call psb_erractionsave(err_act) + + ictxt = desc_a%get_context() + icomm = desc_a%get_mpic() + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (.not.psb_is_asb_desc(desc_a)) then + info=psb_err_invalid_cd_state_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + end if + + call desc_a%get_list(data_,d_idx,totxch,idxr,idxs,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='psb_cd_get_list') + goto 9999 + end if + + call psi_swapdata(ictxt,icomm,flag,beta,y,d_idx,totxch,idxs,idxr,work,info) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2swapdatav + + +! +! +! Subroutine: psi_i2swapdataidxv +! Does the data exchange among processes. +! +! The real workhorse: the outer routines will only choose the index list +! this one takes the index list and does the actual exchange. +! +! +! +subroutine psi_i2swapidxv(iictxt,iicomm,flag,beta,y,idx, & + & totxch,totsnd,totrcv,work,info) + + use psi_mod, psb_protect_name => psi_i2swapidxv + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: iictxt,iicomm,flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_), target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd, totrcv + + ! locals + integer(psb_mpk_) :: ictxt, icomm, np, me,& + & proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret + integer(psb_mpk_), allocatable, dimension(:) :: bsdidx, brvidx,& + & sdsz, rvsz, prcid, rvhd, sdhd + integer(psb_ipk_) :: nesd, nerv,& + & err_act, i, idx_pt, totsnd_, totrcv_,& + & snd_pt, rcv_pt, pnti, n + logical :: swap_mpi, swap_sync, swap_send, swap_recv,& + & albf,do_send,do_recv + logical, parameter :: usersend=.false. + + integer(psb_i2pk_), pointer, dimension(:) :: sndbuf, rcvbuf +#ifdef HAVE_VOLATILE + volatile :: sndbuf, rcvbuf +#endif + character(len=20) :: name + + info=psb_success_ + name='psi_swap_datav' + call psb_erractionsave(err_act) + ictxt = iictxt + icomm = iicomm + + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + n=1 + swap_mpi = iand(flag,psb_swap_mpi_) /= 0 + swap_sync = iand(flag,psb_swap_sync_) /= 0 + swap_send = iand(flag,psb_swap_send_) /= 0 + swap_recv = iand(flag,psb_swap_recv_) /= 0 + do_send = swap_mpi .or. swap_sync .or. swap_send + do_recv = swap_mpi .or. swap_sync .or. swap_recv + + totrcv_ = totrcv * n + totsnd_ = totsnd * n + + if (swap_mpi) then + allocate(sdsz(0:np-1), rvsz(0:np-1), bsdidx(0:np-1),& + & brvidx(0:np-1), rvhd(0:np-1), sdhd(0:np-1), prcid(0:np-1),& + & stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + rvhd(:) = mpi_request_null + sdsz(:) = 0 + rvsz(:) = 0 + + ! prepare info for communications + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(proc_to_comm) = psb_get_mpi_rank(ictxt,proc_to_comm) + + brvidx(proc_to_comm) = rcv_pt + rvsz(proc_to_comm) = nerv + + bsdidx(proc_to_comm) = snd_pt + sdsz(proc_to_comm) = nesd + + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + + end do + + else + allocate(rvhd(totxch),prcid(totxch),stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + end if + + + totrcv_ = max(totrcv_,1) + totsnd_ = max(totsnd_,1) + if((totrcv_+totsnd_) < size(work)) then + sndbuf => work(1:totsnd_) + rcvbuf => work(totsnd_+1:totsnd_+totrcv_) + albf=.false. + else + allocate(sndbuf(totsnd_),rcvbuf(totrcv_), stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + albf=.true. + end if + + + if (do_send) then + + ! Pack send buffers + pnti = 1 + snd_pt = 1 + do i=1, totxch + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+nerv+psb_n_elem_send_ + call psi_gth(nesd,idx(idx_pt:idx_pt+nesd-1),& + & y,sndbuf(snd_pt:snd_pt+nesd-1)) + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + ! Case SWAP_MPI + if (swap_mpi) then + + ! swap elements using mpi_alltoallv + call mpi_alltoallv(sndbuf,sdsz,bsdidx,& + & psb_mpi_i2pk_,rcvbuf,rvsz,& + & brvidx,psb_mpi_i2pk_,icomm,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + + else if (swap_sync) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if (proc_to_comm < me) then + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + else if (proc_to_comm > me) then + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swapdata: mismatch on self send', & + & nerv,nesd + end if + rcvbuf(rcv_pt:rcv_pt+nerv-1) = sndbuf(snd_pt:snd_pt+nesd-1) + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send .and. swap_recv) then + + ! First I post all the non blocking receives + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + prcid(i) = psb_get_mpi_rank(ictxt,proc_to_comm) + if ((nerv>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + call mpi_irecv(rcvbuf(rcv_pt),nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag, icomm,rvhd(i),iret) + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + ! Then I post all the blocking sends + if (usersend) call mpi_barrier(icomm,iret) + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + p2ptag = psb_int2_swap_tag + + if ((nesd>0).and.(proc_to_comm /= me)) then + if (usersend) then + call mpi_rsend(sndbuf(snd_pt),nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + else + call mpi_send(sndbuf(snd_pt),nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + end if + + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + pnti = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + p2ptag = psb_int2_swap_tag + + if ((proc_to_comm /= me).and.(nerv>0)) then + call mpi_wait(rvhd(i),p2pstat,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swapdata: mismatch on self send', & + & nerv,nesd + end if + rcvbuf(rcv_pt:rcv_pt+nerv-1) = sndbuf(snd_pt:snd_pt+nesd-1) + end if + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nesd>0) call psb_snd(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + else if (swap_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nerv>0) call psb_rcv(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (do_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+psb_n_elem_recv_ + call psi_sct(nerv,idx(idx_pt:idx_pt+nerv-1),& + & rcvbuf(rcv_pt:rcv_pt+nerv-1),beta,y) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (swap_mpi) then + deallocate(sdsz,rvsz,bsdidx,brvidx,rvhd,prcid,sdhd,& + & stat=info) + else + deallocate(rvhd,prcid,stat=info) + end if + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + if(albf) deallocate(sndbuf,rcvbuf,stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(iictxt,err_act) + + return +end subroutine psi_i2swapidxv diff --git a/base/comm/internals/psi_i2swaptran_a.F90 b/base/comm/internals/psi_i2swaptran_a.F90 new file mode 100644 index 000000000..f69b8aec6 --- /dev/null +++ b/base/comm/internals/psi_i2swaptran_a.F90 @@ -0,0 +1,1006 @@ +! +! 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. +! +! +! +! File: psi_i2swaptran.F90 +! +! Subroutine: psi_i2swaptranm +! Implements the data exchange among processes. This is similar to Xswapdata, but +! the list is read "in reverse", i.e. indices that are normally SENT are used +! for the RECEIVE part and vice-versa. This is the basic data exchange operation +! for doing the product of a sparse matrix by a vector. +! Essentially this is doing a variable all-to-all data exchange +! (ALLTOALLV in MPI parlance), but +! it is capable of pruning empty exchanges, which are very likely in out +! application environment. All the variants have the same structure +! In all these subroutines X may be: I Integer +! S real(psb_spk_) +! D real(psb_dpk_) +! C complex(psb_spk_) +! Z complex(psb_dpk_) +! Basically the operation is as follows: on each process, we identify +! sections SND(Y) and RCV(Y); then we do a SEND(PACK(SND(Y))); +! then we receive, and we do an update with Y = UNPACK(RCV(Y)) + BETA * Y +! but only on the elements involved in the UNPACK operation. +! Thus: for halo data exchange, the receive section is confined in the +! halo indices, and BETA=0, whereas for overlap exchange the receive section +! is scattered in the owned indices, and BETA=1. +! The first routine picks the desired exchange index list and passes it to the second. +! +! Arguments: +! flag - integer Choose the algorithm for data exchange: +! this is chosen through bit fields. +! swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! swap_sync = iand(flag,psb_swap_sync_) /= 0 +! swap_send = iand(flag,psb_swap_send_) /= 0 +! swap_recv = iand(flag,psb_swap_recv_) /= 0 +! if (swap_mpi): use underlying MPI_ALLTOALLV. +! if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +! n - integer Number of columns in Y +! beta - integer Choose overwrite or sum. +! y(:,:) - integer The data area +! desc_a - type(psb_desc_type). The communication descriptor. +! work(:) - integer Buffer space. If not sufficient, will do +! our own internal allocation. +! info - integer. return code. +! data - integer which list is to be used to exchange data +! default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psi_i2swaptranm(flag,n,beta,y,desc_a,work,info,data) + + use psi_mod, psb_protect_name => psi_i2swaptranm + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_), target :: work(:) + type(psb_desc_type),target :: desc_a + integer(psb_ipk_), optional :: data + + ! locals + integer(psb_ipk_) :: ictxt, np, me, icomm, idxs, idxr, err_act, totxch, data_ + integer(psb_ipk_), pointer :: d_idx(:) + character(len=20) :: name + + info=psb_success_ + name='psi_swap_tran' + call psb_erractionsave(err_act) + + ictxt = desc_a%get_context() + icomm = desc_a%get_mpic() + + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (.not.psb_is_asb_desc(desc_a)) then + info=psb_err_invalid_cd_state_ + call psb_errpush(info,name) + goto 9999 + endif + + if(present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + end if + + call desc_a%get_list(data_,d_idx,totxch,idxr,idxs,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='psb_cd_get_list') + goto 9999 + end if + + call psi_swaptran(ictxt,icomm,flag,n,beta,y,d_idx,totxch,idxs,idxr,work,info) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2swaptranm + +subroutine psi_i2tranidxm(iictxt,iicomm,flag,n,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + + use psi_mod, psb_protect_name => psi_i2tranidxm + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: iictxt,iicomm,flag,n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_), target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd, totrcv + + ! locals + integer(psb_mpk_) :: ictxt, icomm, np, me,& + & proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret + integer(psb_mpk_), allocatable, dimension(:) :: bsdidx, brvidx,& + & sdsz, rvsz, prcid, rvhd, sdhd + integer(psb_ipk_) :: nesd, nerv,& + & err_act, i, idx_pt, totsnd_, totrcv_,& + & snd_pt, rcv_pt, pnti + logical :: swap_mpi, swap_sync, swap_send, swap_recv,& + & albf,do_send,do_recv + logical, parameter :: usersend=.false. + + integer(psb_i2pk_), pointer, dimension(:) :: sndbuf, rcvbuf +#ifdef HAVE_VOLATILE + volatile :: sndbuf, rcvbuf +#endif + character(len=20) :: name + + info=psb_success_ + name='psi_swap_tran' + call psb_erractionsave(err_act) + ictxt = iictxt + icomm = iicomm + + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + swap_mpi = iand(flag,psb_swap_mpi_) /= 0 + swap_sync = iand(flag,psb_swap_sync_) /= 0 + swap_send = iand(flag,psb_swap_send_) /= 0 + swap_recv = iand(flag,psb_swap_recv_) /= 0 + + do_send = swap_mpi .or. swap_sync .or. swap_send + do_recv = swap_mpi .or. swap_sync .or. swap_recv + + totrcv_ = totrcv * n + totsnd_ = totsnd * n + + if (swap_mpi) then + allocate(sdsz(0:np-1), rvsz(0:np-1), bsdidx(0:np-1),& + & brvidx(0:np-1), rvhd(0:np-1), sdhd(0:np-1), prcid(0:np-1),& + & stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + rvhd(:) = mpi_request_null + sdsz(:) = 0 + rvsz(:) = 0 + + ! prepare info for communications + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(proc_to_comm) = psb_get_mpi_rank(ictxt,proc_to_comm) + + brvidx(proc_to_comm) = rcv_pt + rvsz(proc_to_comm) = n*nerv + + bsdidx(proc_to_comm) = snd_pt + sdsz(proc_to_comm) = n*nesd + + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + else + allocate(rvhd(totxch),prcid(totxch),stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + end if + + totrcv_ = max(totrcv_,1) + totsnd_ = max(totsnd_,1) + if((totrcv_+totsnd_) < size(work)) then + sndbuf => work(1:totsnd_) + rcvbuf => work(totsnd_+1:totsnd_+totrcv_) + albf=.false. + else + allocate(sndbuf(totsnd_),rcvbuf(totrcv_), stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + albf=.true. + end if + + if (do_send) then + + ! Pack send buffers + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+psb_n_elem_recv_ + + call psi_gth(nerv,n,idx(idx_pt:idx_pt+nerv-1),& + & y,rcvbuf(rcv_pt:rcv_pt+n*nerv-1)) + + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + + + ! Case SWAP_MPI + if (swap_mpi) then + + ! swap elements using mpi_alltoallv + call mpi_alltoallv(rcvbuf,rvsz,brvidx,& + & psb_mpi_i2pk_,& + & sndbuf,sdsz,bsdidx,psb_mpi_i2pk_,icomm,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + + else if (swap_sync) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if (proc_to_comm < me) then + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + else if (proc_to_comm > me) then + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swaptran: mismatch on self send', & + & nerv,nesd + end if + sndbuf(snd_pt:snd_pt+n*nesd-1) = rcvbuf(rcv_pt:rcv_pt+n*nerv-1) + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + + else if (swap_send .and. swap_recv) then + + ! First I post all the non blocking receives + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(i) = psb_get_mpi_rank(ictxt,proc_to_comm) + if ((nesd>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + call mpi_irecv(sndbuf(snd_pt),n*nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,rvhd(i),iret) + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + + ! Then I post all the blocking sends + if (usersend) call mpi_barrier(icomm,iret) + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if ((nerv>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + if (usersend) then + call mpi_rsend(rcvbuf(rcv_pt),n*nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + else + call mpi_send(rcvbuf(rcv_pt),n*nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,iret) + end if + + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + end if + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + + pnti = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + p2ptag = psb_int2_swap_tag + + if ((proc_to_comm /= me).and.(nesd>0)) then + call mpi_wait(rvhd(i),p2pstat,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swaptran: mismatch on self send',& + & nerv,nesd + end if + sndbuf(snd_pt:snd_pt+n*nesd-1) = rcvbuf(rcv_pt:rcv_pt+n*nerv-1) + end if + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+n*nerv-1), proc_to_comm) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + + end do + + else if (swap_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+n*nesd-1), proc_to_comm) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (do_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+nerv+psb_n_elem_send_ + call psi_sct(nesd,n,idx(idx_pt:idx_pt+nesd-1),& + & sndbuf(snd_pt:snd_pt+n*nesd-1),beta,y) + rcv_pt = rcv_pt + n*nerv + snd_pt = snd_pt + n*nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + + if (swap_mpi) then + deallocate(sdsz,rvsz,bsdidx,brvidx,rvhd,prcid,sdhd,& + & stat=info) + else + deallocate(rvhd,prcid,stat=info) + end if + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + if(albf) deallocate(sndbuf,rcvbuf,stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(iictxt,err_act) + + return +end subroutine psi_i2tranidxm +! +! +! Subroutine: psi_i2swaptranv +! Implements the data exchange among processes. This is similar to Xswapdata, but +! the list is read "in reverse", i.e. indices that are normally SENT are used +! for the RECEIVE part and vice-versa. This is the basic data exchange operation +! for doing the product of a sparse matrix by a vector. +! Essentially this is doing a variable all-to-all data exchange +! (ALLTOALLV in MPI parlance), but +! it is capable of pruning empty exchanges, which are very likely in out +! application environment. All the variants have the same structure +! In all these subroutines X may be: I Integer +! S real(psb_spk_) +! D real(psb_dpk_) +! C complex(psb_spk_) +! Z complex(psb_dpk_) +! Basically the operation is as follows: on each process, we identify +! sections SND(Y) and RCV(Y); then we do a SEND(PACK(SND(Y))); +! then we receive, and we do an update with Y = UNPACK(RCV(Y)) + BETA * Y +! but only on the elements involved in the UNPACK operation. +! Thus: for halo data exchange, the receive section is confined in the +! halo indices, and BETA=0, whereas for overlap exchange the receive section +! is scattered in the owned indices, and BETA=1. +! The first routine picks the desired exchange index list and passes it to the second. +! +! Arguments: +! flag - integer Choose the algorithm for data exchange: +! this is chosen through bit fields. +! swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! swap_sync = iand(flag,psb_swap_sync_) /= 0 +! swap_send = iand(flag,psb_swap_send_) /= 0 +! swap_recv = iand(flag,psb_swap_recv_) /= 0 +! if (swap_mpi): use underlying MPI_ALLTOALLV. +! if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +! n - integer Number of columns in Y +! beta - integer Choose overwrite or sum. +! y(:) - integer The data area +! desc_a - type(psb_desc_type). The communication descriptor. +! work(:) - integer Buffer space. If not sufficient, will do +! our own internal allocation. +! info - integer. return code. +! data - integer which list is to be used to exchange data +! default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psi_i2swaptranv(flag,beta,y,desc_a,work,info,data) + + use psi_mod, psb_protect_name => psi_i2swaptranv + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_), target :: work(:) + type(psb_desc_type),target :: desc_a + integer(psb_ipk_), optional :: data + + ! locals + integer(psb_ipk_) :: ictxt, np, me, icomm, idxs, idxr, totxch, err_act, data_ + integer(psb_ipk_), pointer :: d_idx(:) + character(len=20) :: name + + info=psb_success_ + name='psi_swap_tranv' + call psb_erractionsave(err_act) + + ictxt = desc_a%get_context() + icomm = desc_a%get_mpic() + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (.not.psb_is_asb_desc(desc_a)) then + info=psb_err_invalid_cd_state_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + end if + + call desc_a%get_list(data_,d_idx,totxch,idxr,idxs,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='psb_cd_get_list') + goto 9999 + end if + + call psi_swaptran(ictxt,icomm,flag,beta,y,d_idx,totxch,idxs,idxr,work,info) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psi_i2swaptranv + + +! +! +! Subroutine: psi_i2tranidxv +! Does the data exchange among processes. +! +! The real workhorse: the outer routines will only choose the index list +! this one takes the index list and does the actual exchange. +! +! +! +subroutine psi_i2tranidxv(iictxt,iicomm,flag,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + + use psi_mod, psb_protect_name => psi_i2tranidxv + use psb_error_mod + use psb_desc_mod + use psb_penv_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_ipk_), intent(in) :: iictxt,iicomm,flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_), target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd, totrcv + + ! locals + integer(psb_mpk_) :: ictxt, icomm, np, me,& + & proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret + integer(psb_mpk_), allocatable, dimension(:) :: bsdidx, brvidx,& + & sdsz, rvsz, prcid, rvhd, sdhd + integer(psb_ipk_) :: nesd, nerv,& + & err_act, i, idx_pt, totsnd_, totrcv_,& + & snd_pt, rcv_pt, pnti, n + logical :: swap_mpi, swap_sync, swap_send, swap_recv,& + & albf,do_send,do_recv + logical, parameter :: usersend=.false. + + integer(psb_i2pk_), pointer, dimension(:) :: sndbuf, rcvbuf +#ifdef HAVE_VOLATILE + volatile :: sndbuf, rcvbuf +#endif + character(len=20) :: name + + info=psb_success_ + name='psi_swap_tran' + call psb_erractionsave(err_act) + ictxt = iictxt + icomm = iicomm + + call psb_info(ictxt,me,np) + if (np == -1) then + info=psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + n=1 + swap_mpi = iand(flag,psb_swap_mpi_) /= 0 + swap_sync = iand(flag,psb_swap_sync_) /= 0 + swap_send = iand(flag,psb_swap_send_) /= 0 + swap_recv = iand(flag,psb_swap_recv_) /= 0 + do_send = swap_mpi .or. swap_sync .or. swap_send + do_recv = swap_mpi .or. swap_sync .or. swap_recv + + totrcv_ = totrcv * n + totsnd_ = totsnd * n + + if (swap_mpi) then + allocate(sdsz(0:np-1), rvsz(0:np-1), bsdidx(0:np-1),& + & brvidx(0:np-1), rvhd(0:np-1), sdhd(0:np-1), prcid(0:np-1),& + & stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + rvhd(:) = mpi_request_null + sdsz(:) = 0 + rvsz(:) = 0 + + ! prepare info for communications + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(proc_to_comm) = psb_get_mpi_rank(ictxt,proc_to_comm) + + brvidx(proc_to_comm) = rcv_pt + rvsz(proc_to_comm) = nerv + + bsdidx(proc_to_comm) = snd_pt + sdsz(proc_to_comm) = nesd + + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + + end do + + else + allocate(rvhd(totxch),prcid(totxch),stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + end if + + + totrcv_ = max(totrcv_,1) + totsnd_ = max(totsnd_,1) + if((totrcv_+totsnd_) < size(work)) then + sndbuf => work(1:totsnd_) + rcvbuf => work(totsnd_+1:totsnd_+totrcv_) + albf=.false. + else + allocate(sndbuf(totsnd_),rcvbuf(totrcv_), stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + albf=.true. + end if + + + if (do_send) then + + ! Pack send buffers + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+psb_n_elem_recv_ + + call psi_gth(nerv,idx(idx_pt:idx_pt+nerv-1),& + & y,rcvbuf(rcv_pt:rcv_pt+nerv-1)) + + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + ! Case SWAP_MPI + if (swap_mpi) then + + ! swap elements using mpi_alltoallv + call mpi_alltoallv(rcvbuf,rvsz,brvidx,& + & psb_mpi_i2pk_,& + & sndbuf,sdsz,bsdidx,psb_mpi_i2pk_,icomm,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + + else if (swap_sync) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if (proc_to_comm < me) then + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + else if (proc_to_comm > me) then + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swaptran: mismatch on self send', & + & nerv,nesd + end if + sndbuf(snd_pt:snd_pt+nesd-1) = rcvbuf(rcv_pt:rcv_pt+nerv-1) + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send .and. swap_recv) then + + ! First I post all the non blocking receives + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + prcid(i) = psb_get_mpi_rank(ictxt,proc_to_comm) + if ((nesd>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + call mpi_irecv(sndbuf(snd_pt),nesd,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag,icomm,rvhd(i),iret) + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + ! Then I post all the blocking sends + if (usersend) call mpi_barrier(icomm,iret) + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + + if ((nerv>0).and.(proc_to_comm /= me)) then + p2ptag = psb_int2_swap_tag + if (usersend) then + call mpi_rsend(rcvbuf(rcv_pt),nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag, icomm,iret) + else + call mpi_send(rcvbuf(rcv_pt),nerv,& + & psb_mpi_i2pk_,prcid(i),& + & p2ptag, icomm,iret) + end if + + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + end if + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + + pnti = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + p2ptag = psb_int2_swap_tag + + if ((proc_to_comm /= me).and.(nesd>0)) then + call mpi_wait(rvhd(i),p2pstat,iret) + if(iret /= mpi_success) then + info=psb_err_mpi_error_ + call psb_errpush(info,name,m_err=(/iret/)) + goto 9999 + end if + else if (proc_to_comm == me) then + if (nesd /= nerv) then + write(psb_err_unit,*) & + & 'Fatal error in swaptran: mismatch on self send', & + & nerv,nesd + end if + sndbuf(snd_pt:snd_pt+nesd-1) = rcvbuf(rcv_pt:rcv_pt+nerv-1) + end if + pnti = pnti + nerv + nesd + 3 + end do + + + else if (swap_send) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nerv>0) call psb_snd(ictxt,& + & rcvbuf(rcv_pt:rcv_pt+nerv-1), proc_to_comm) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + else if (swap_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + if (nesd>0) call psb_rcv(ictxt,& + & sndbuf(snd_pt:snd_pt+nesd-1), proc_to_comm) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (do_recv) then + + pnti = 1 + snd_pt = 1 + rcv_pt = 1 + do i=1, totxch + proc_to_comm = idx(pnti+psb_proc_id_) + nerv = idx(pnti+psb_n_elem_recv_) + nesd = idx(pnti+nerv+psb_n_elem_send_) + idx_pt = 1+pnti+nerv+psb_n_elem_send_ + call psi_sct(nesd,idx(idx_pt:idx_pt+nesd-1),& + & sndbuf(snd_pt:snd_pt+nesd-1),beta,y) + rcv_pt = rcv_pt + nerv + snd_pt = snd_pt + nesd + pnti = pnti + nerv + nesd + 3 + end do + + end if + + if (swap_mpi) then + deallocate(sdsz,rvsz,bsdidx,brvidx,rvhd,prcid,sdhd,& + & stat=info) + else + deallocate(rvhd,prcid,stat=info) + end if + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + if(albf) deallocate(sndbuf,rcvbuf,stat=info) + if(info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(iictxt,err_act) + + return +end subroutine psi_i2tranidxv diff --git a/base/comm/psb_cspgather.F90 b/base/comm/psb_cspgather.F90 index 45dcc667a..23ab271fc 100644 --- a/base/comm/psb_cspgather.F90 +++ b/base/comm/psb_cspgather.F90 @@ -70,7 +70,7 @@ subroutine psb_csp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_csp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_csp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_csp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_lcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_lcsp_allgather subroutine psb_lclcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_lclcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_lclcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_lclcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_lclcsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/comm/psb_dspgather.F90 b/base/comm/psb_dspgather.F90 index 62084d481..11eedaf4a 100644 --- a/base/comm/psb_dspgather.F90 +++ b/base/comm/psb_dspgather.F90 @@ -70,7 +70,7 @@ subroutine psb_dsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_dsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_dsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_dsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_ldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_ldsp_allgather subroutine psb_ldldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_ldldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_ldldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_ldldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_ldldsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/comm/psb_i2gather_a.f90 b/base/comm/psb_i2gather_a.f90 new file mode 100644 index 000000000..9a671ef60 --- /dev/null +++ b/base/comm/psb_i2gather_a.f90 @@ -0,0 +1,335 @@ +! +! 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. +! +! +! File: psb_i2gather.f90 +! +! Subroutine: psb_i2gather +! This subroutine gathers pieces of a distributed dense matrix into a local one. +! +! Arguments: +! globx - integer,dimension(:,:). The local matrix into which gather +! the distributed pieces. +! locx - integer,dimension(:,:). The local piece of the distributed +! matrix to be gathered. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Error code. +! iroot - integer. The process that has to own the +! global matrix. If -1 all +! the processes will have a copy. +! +subroutine psb_i2gatherm(globx, locx, desc_a, info, iroot) + use psb_base_mod, psb_protect_name => psb_i2gatherm + implicit none + + integer(psb_i2pk_), intent(in) :: locx(:,:) + integer(psb_i2pk_), intent(out), allocatable :: globx(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: iroot + + + ! locals + integer(psb_mpk_) :: ictxt, np, me, root, iiroot, icomm, myrank, rootrank + integer(psb_ipk_) :: ierr(5), err_act, lda_locx, lda_globx, lock, globk,& + & maxk, k, jlx, ilx, i, j + integer(psb_lpk_) :: m, n, ilocx, jlocx, idx, iglobx, jglobx + + character(len=20) :: name, ch_err + + name='psb_i2gatherm' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(iroot)) then + root = iroot + if((root < -1).or.(root > np)) then + info=psb_err_input_value_invalid_i_ + ierr(1) = 5; ierr(2)=root + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + else + root = -1 + end if + if (root == -1) then + iiroot = psb_root_ + else + iiroot = root + endif + + iglobx = 1 + jglobx = 1 + ilocx = 1 + jlocx = 1 + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + lda_globx = m + lda_locx = size(locx, 1) + lock = size(locx,2) + maxk = lock + k = maxk + + call psb_bcast(ictxt,k,root=iiroot) + + ! there should be a global check on k here!!! + + call psb_chkglobvect(m,n,lda_globx,iglobx,jglobx,desc_a,info) + if (info == psb_success_) & + & call psb_chkvect(m,n,lda_locx,ilocx,jlocx,desc_a,info,ilx,jlx) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_chk(glob)vect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + if ((ilx /= 1).or.(iglobx /= 1)) then + info=psb_err_ix_n1_iy_n1_unsupported_ + call psb_errpush(info,name) + goto 9999 + end if + + call psb_realloc(m,k,globx,info) + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + globx(:,:)=i2zero + + do j=1,k + do i=1,desc_a%get_local_rows() + call psb_loc_to_glob(i,idx,desc_a,info) + globx(idx,j) = locx(i,jlx+j-1) + end do + end do + + do j=1,k + ! adjust overlapped elements + do i=1, size(desc_a%ovrlap_elem,1) + if (me /= desc_a%ovrlap_elem(i,3)) then + idx = desc_a%ovrlap_elem(i,1) + call psb_loc_to_glob(idx,desc_a,info) + globx(idx,j) = i2zero + end if + end do + end do + + call psb_sum(ictxt,globx(1:m,1:k),root=root) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return + +end subroutine psb_i2gatherm + + + + + + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! Subroutine: psb_i2gatherv +! This subroutine gathers pieces of a distributed dense vector into a local one. +! +! Arguments: +! globx - integer,dimension(:). The local vector into which gather +! the distributed pieces. +! locx - integer,dimension(:). The local piece of the distributed +! vector to be gathered. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Error code. +! iroot - integer. The process that has to own the +! global matrix. If -1 all +! the processes will have a copy. +! default: -1 +! +subroutine psb_i2gatherv(globx, locx, desc_a, info, iroot) + use psb_base_mod, psb_protect_name => psb_i2gatherv + implicit none + + integer(psb_i2pk_), intent(in) :: locx(:) + integer(psb_i2pk_), intent(out), allocatable :: globx(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: iroot + + + ! locals + integer(psb_mpk_) :: ictxt, np, me, root, iiroot, icomm, myrank, rootrank + integer(psb_ipk_) :: ierr(5), err_act, lda_locx, lda_globx, lock, globk,& + & maxk, k, jlx, ilx, i, j + integer(psb_lpk_) :: m, n, ilocx, jlocx, idx, iglobx, jglobx + + character(len=20) :: name, ch_err + + name='psb_i2gatherv' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(iroot)) then + root = iroot + if((root < -1).or.(root > np)) then + info=psb_err_input_value_invalid_i_ + ierr(1)=5; ierr(2)=root + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + else + root = -1 + end if + + jglobx=1 + iglobx = 1 + jlocx=1 + ilocx = 1 + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + + lda_globx = m + lda_locx = size(locx) + + k = 1 + + + ! there should be a global check on k here!!! + + call psb_chkglobvect(m,n,lda_globx,iglobx,jglobx,desc_a,info) + if (info == psb_success_) & + & call psb_chkvect(m,n,lda_locx,ilocx,jlocx,desc_a,info,ilx,jlx) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_chk(glob)vect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + if ((ilx /= 1).or.(iglobx /= 1)) then + info=psb_err_ix_n1_iy_n1_unsupported_ + call psb_errpush(info,name) + goto 9999 + end if + + call psb_realloc(m,globx,info) + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + globx(:)=i2zero + + do i=1,desc_a%get_local_rows() + call psb_loc_to_glob(i,idx,desc_a,info) + globx(idx) = locx(i) + end do + + ! adjust overlapped elements + do i=1, size(desc_a%ovrlap_elem,1) + if (me /= desc_a%ovrlap_elem(i,3)) then + idx = desc_a%ovrlap_elem(i,1) + call psb_loc_to_glob(idx,desc_a,info) + globx(idx) = i2zero + end if + end do + + call psb_sum(ictxt,globx(1:m),root=root) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return + +end subroutine psb_i2gatherv + diff --git a/base/comm/psb_i2halo_a.f90 b/base/comm/psb_i2halo_a.f90 new file mode 100644 index 000000000..f9c17fa5e --- /dev/null +++ b/base/comm/psb_i2halo_a.f90 @@ -0,0 +1,380 @@ +! +! 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. +! +! +! File: psb_i2halo.f90 +! +! Subroutine: psb_i2halom +! This subroutine performs the exchange of the halo elements in a +! distributed dense matrix between all the processes. +! +! Arguments: +! x - integer,dimension(:,:). The local part of the dense matrix. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +! jx - integer(optional). The starting column of the global matrix. +! ik - integer(optional). The number of columns to gather. +! work - integer(optional). Work area. +! tran - character(optional). Transpose exchange. +! mode - integer(optional). Communication mode (see Swapdata) +! data - integer Which index list in desc_a should be used +! to retrieve rows, default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psb_i2halom(x,desc_a,info,jx,ik,work,tran,mode,data) + use psb_base_mod, psb_protect_name => psb_i2halom + use psi_mod + implicit none + + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), optional, target, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: mode,jx,ik,data + character, intent(in), optional :: tran + + ! locals + integer(psb_mpk_) :: ictxt, np, me + integer(psb_ipk_) :: err_act, iix, jjx, k, maxk, nrow, imode, i,& + & liwork,data_, ldx + integer(psb_lpk_) :: m, n, ix, ijx + integer(psb_i2pk_),pointer :: iwork(:), xp(:,:) + character :: tran_ + character(len=20) :: name, ch_err + logical :: aliw + + name='psb_i2halom' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ix = 1 + if (present(jx)) then + ijx = jx + else + ijx = 1 + endif + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + nrow = desc_a%get_local_rows() + + maxk=size(x,2)-ijx+1 + + if(present(ik)) then + if(ik > maxk) then + k=maxk + else + k=ik + end if + else + k = maxk + end if + + if (present(tran)) then + tran_ = psb_toupper(tran) + else + tran_ = 'N' + endif + if (present(mode)) then + imode = mode + else + imode = IOR(psb_swap_send_,psb_swap_recv_) + endif + + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + ldx = size(x,1) + ! check vector correctness + call psb_chkvect(m,lone,ldx,ix,ijx,desc_a,info,iix,jjx,check_halo=.true.) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ ; ch_err='psb_chkvect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + liwork=nrow + if (present(work)) then + if(size(work) >= liwork) then + aliw=.false. + iwork => work + else + aliw=.true. + allocate(iwork(liwork),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_realloc' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + else + aliw=.true. + allocate(iwork(liwork),stat=info) + + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_realloc' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + + ! exchange halo elements + xp => x(iix:size(x,1),jjx:jjx+k-1) + if(tran_ == 'N') then + call psi_swapdata(imode,k,i2zero,xp,& + & desc_a,iwork,info,data=data_) + else if((tran_ == 'T').or.(tran_ == 'C')) then + call psi_swaptran(imode,k,i2one,xp,& + &desc_a,iwork,info) + else + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='invalid tran') + goto 9999 + end if + + if(info /= psb_success_) then + ch_err='PSI_cswapdata' + call psb_errpush(psb_err_from_subroutine_,name,a_err=ch_err) + goto 9999 + end if + + if (aliw) deallocate(iwork) + nullify(iwork) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return +end subroutine psb_i2halom + + + + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! +! Subroutine: psb_i2halov +! This subroutine performs the exchange of the halo elements in a +! distributed dense vector between all the processes. +! +! Arguments: +! x - real,dimension(:). The local part of the dense vector. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +! jx - integer(optional). The starting column of the global matrix. +! ik - integer(optional). The number of columns to gather. +! work - integer(optional). Work area. +! tran - character(optional). Transpose exchange. +! mode - integer(optional). Communication mode (see Swapdata) +! data - integer Which index list in desc_a should be used +! to retrieve rows, default psb_comm_halo_ +! psb_comm_halo_ use halo_index +! psb_comm_ext_ use ext_index +! psb_comm_ovrl_ use ovrl_index +! psb_comm_mov_ use ovr_mst_idx +! +! +subroutine psb_i2halov(x,desc_a,info,work,tran,mode,data) + use psb_base_mod, psb_protect_name => psb_i2halov + use psi_mod + implicit none + + integer(psb_i2pk_), intent(inout) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), target, optional, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: mode,data + character, intent(in), optional :: tran + + ! locals + integer(psb_mpk_) :: ictxt, np, me + integer(psb_ipk_) :: err_act, ldx, iix, jjx, nrow, imode, liwork,data_ + integer(psb_lpk_) :: m, n, ix, ijx + integer(psb_i2pk_),pointer :: iwork(:) + character :: tran_ + character(len=20) :: name, ch_err + logical :: aliw + + name='psb_i2halov' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ix = 1 + ijx = 1 + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + nrow = desc_a%get_local_rows() + + if (present(tran)) then + tran_ = psb_toupper(tran) + else + tran_ = 'N' + endif + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + if (present(mode)) then + imode = mode + else + imode = IOR(psb_swap_send_,psb_swap_recv_) + endif + ldx = size(x,1) + ! check vector correctness + call psb_chkvect(m,lone,ldx,ix,ijx,desc_a,info,iix,jjx,check_halo=.true.) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ ; ch_err='psb_chkvect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + liwork=nrow + if (present(work)) then + if(size(work) >= liwork) then + aliw=.false. + iwork => work + else + aliw=.true. + allocate(iwork(liwork),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_realloc' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + else + aliw=.true. + allocate(iwork(liwork),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_realloc' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + + ! exchange halo elements + if(tran_ == 'N') then + call psi_swapdata(imode,i2zero,x(iix:size(x)),& + & desc_a,iwork,info,data=data_) + else if((tran_ == 'T').or.(tran_ == 'C')) then + call psi_swaptran(imode,i2one,x(iix:size(x)),& + & desc_a,iwork,info) + else + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='invalid tran') + goto 9999 + end if + + if(info /= psb_success_) then + ch_err='PSI_swapdata' + call psb_errpush(psb_err_from_subroutine_,name,a_err=ch_err) + goto 9999 + end if + + if (aliw) deallocate(iwork) + nullify(iwork) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return +end subroutine psb_i2halov + diff --git a/base/comm/psb_i2ovrl_a.f90 b/base/comm/psb_i2ovrl_a.f90 new file mode 100644 index 000000000..8d056e39f --- /dev/null +++ b/base/comm/psb_i2ovrl_a.f90 @@ -0,0 +1,374 @@ +! +! 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. +! +! +! +! File: psb_i2ovrl.f90 +! +! Subroutine: psb_i2ovrlm +! This subroutine performs the exchange of the overlap elements in a +! distributed dense matrix between all the processes. +! +! Arguments: +! x(:,:) - integer The local part of the dense matrix. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code. +! jx - integer(optional). The starting column of the global matrix +! ik - integer(optional). The number of columns to gather. +! work - integer(optional). A work area. +! update - integer(optional). Type of update: +! psb_none_ do nothing +! psb_sum_ sum of overlaps +! psb_avg_ average of overlaps +! mode - integer(optional). Choose the algorithm for data exchange: +! this is chosen through bit fields. +! - swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! - swap_sync = iand(flag,psb_swap_sync_) /= 0 +! - swap_send = iand(flag,psb_swap_send_) /= 0 +! - swap_recv = iand(flag,psb_swap_recv_) /= 0 +! - if (swap_mpi): use underlying MPI_ALLTOALLV. +! - if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! - if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! - if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! - if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +subroutine psb_i2ovrlm(x,desc_a,info,jx,ik,work,update,mode) + use psb_base_mod, psb_protect_name => psb_i2ovrlm + use psi_mod + implicit none + + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), optional, target, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: update,jx,ik,mode + + ! locals + integer(psb_mpk_) :: ictxt, np, me + integer(psb_ipk_) :: err_act, iix, jjx, nrow, ncol, k, maxk, update_,& + & mode_, liwork, ldx + integer(psb_lpk_) :: m, n, ix, ijx + integer(psb_i2pk_),pointer :: iwork(:), xp(:,:) + logical :: do_swap + character(len=20) :: name, ch_err + logical :: aliw + + name='psb_i2ovrlm' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ix = 1 + if (present(jx)) then + ijx = jx + else + ijx = 1 + endif + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + + maxk=size(x,2)-ijx+1 + + if(present(ik)) then + if(ik > maxk) then + k=maxk + else + k=ik + end if + else + k = maxk + end if + + if (present(update)) then + update_ = update + else + update_ = psb_avg_ + endif + + if (present(mode)) then + mode_ = mode + else + mode_ = IOR(psb_swap_send_,psb_swap_recv_) + endif + do_swap = (mode_ /= 0) + ldx = size(x,1) + ! check vector correctness + call psb_chkvect(m,lone,ldx,ix,ijx,desc_a,info,iix,jjx) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ ; ch_err='psb_chkvect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + ! check for presence/size of a work area + liwork=ncol + if (present(work)) then + if(size(work) >= liwork) then + aliw=.false. + else + aliw=.true. + end if + else + aliw=.true. + end if + + if (aliw) then + allocate(iwork(liwork),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='Allocate') + goto 9999 + end if + else + iwork => work + end if + ! exchange overlap elements + if(do_swap) then + xp => x(iix:ldx,jjx:jjx+k-1) + call psi_swapdata(mode_,k,i2one,xp,& + & desc_a,iwork,info,data=psb_comm_ovr_) + end if + if (info == psb_success_) call psi_ovrl_upd(xp,desc_a,update_,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Inner updates') + goto 9999 + end if + + if (aliw) deallocate(iwork) + nullify(iwork) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return +end subroutine psb_i2ovrlm +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! +! Subroutine: psb_i2ovrlv +! This subroutine performs the exchange of the overlap elements in a +! distributed dense vector between all the processes. +! +! Arguments: +! x(:) - integer The local part of the dense vector. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code. +! work - integer(optional). A work area. +! update - integer(optional). Type of update: +! psb_none_ do nothing +! psb_sum_ sum of overlaps +! psb_avg_ average of overlaps +! mode - integer(optional). Choose the algorithm for data exchange: +! this is chosen through bit fields. +! - swap_mpi = iand(flag,psb_swap_mpi_) /= 0 +! - swap_sync = iand(flag,psb_swap_sync_) /= 0 +! - swap_send = iand(flag,psb_swap_send_) /= 0 +! - swap_recv = iand(flag,psb_swap_recv_) /= 0 +! - if (swap_mpi): use underlying MPI_ALLTOALLV. +! - if (swap_sync): use PSB_SND and PSB_RCV in +! synchronized pairs +! - if (swap_send .and. swap_recv): use mpi_irecv +! and mpi_send +! - if (swap_send): use psb_snd (but need another +! call with swap_recv to complete) +! - if (swap_recv): use psb_rcv (completing a +! previous call with swap_send) +! +! +subroutine psb_i2ovrlv(x,desc_a,info,work,update,mode) + use psb_base_mod, psb_protect_name => psb_i2ovrlv + use psi_mod + implicit none + + integer(psb_i2pk_), intent(inout), target :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), optional, target, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: update,mode + + ! locals + integer(psb_ipk_) :: ictxt, np, me, err_act, iix, jjx, nrow, ncol, & + & k, update_, mode_, liwork, ldx + integer(psb_lpk_) :: m, n, ix, ijx + integer(psb_i2pk_),pointer :: iwork(:) + logical :: do_swap + character(len=20) :: name, ch_err + logical :: aliw + + name='psb_i2ovrlv' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + ix = 1 + ijx = 1 + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + + k = 1 + + if (present(update)) then + update_ = update + else + update_ = psb_avg_ + endif + + if (present(mode)) then + mode_ = mode + else + mode_ = IOR(psb_swap_send_,psb_swap_recv_) + endif + do_swap = (mode_ /= 0) + ldx = size(x,1) + ! check vector correctness + call psb_chkvect(m,lone,ldx,ix,ijx,desc_a,info,iix,jjx) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_chkvect' + call psb_errpush(info,name,a_err=ch_err) + end if + + if (iix /= 1) then + info=psb_err_ix_n1_iy_n1_unsupported_ + call psb_errpush(info,name) + end if + + if(info /= 0) goto 9999 + + + ! check for presence/size of a work area + liwork=ncol + if (present(work)) then + if(size(work) >= liwork) then + aliw=.false. + else + aliw=.true. + end if + else + aliw=.true. + end if + if (aliw) then + allocate(iwork(liwork),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='Allocate') + goto 9999 + end if + else + iwork => work + end if + + ! exchange overlap elements + if (do_swap) then + call psi_swapdata(mode_,i2one,x,& + & desc_a,iwork,info,data=psb_comm_ovr_) + end if + if (info == psb_success_) call psi_ovrl_upd(x,desc_a,update_,info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Inner updates') + goto 9999 + end if + + if (aliw) deallocate(iwork) + nullify(iwork) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return +end subroutine psb_i2ovrlv diff --git a/base/comm/psb_i2scatter_a.F90 b/base/comm/psb_i2scatter_a.F90 new file mode 100644 index 000000000..4a72458ea --- /dev/null +++ b/base/comm/psb_i2scatter_a.F90 @@ -0,0 +1,480 @@ +! +! 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. +! +! +! File: psb_i2scatter.f90 +! +! Subroutine: psb_i2scatterm +! This subroutine scatters a global matrix locally owned by one process +! into pieces that are local to all the processes. +! +! Arguments: +! globx - integer,dimension(:,:). The global matrix to scatter. +! locx - integer,dimension(:,:). The local piece of the distributed matrix. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Error code. +! iroot - integer(optional). The process that owns the global matrix. +! If -1 all the processes have a copy. +! Default -1 +subroutine psb_i2scatterm(globx, locx, desc_a, info, root) + + use psb_base_mod, psb_protect_name => psb_i2scatterm +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_i2pk_), intent(out), allocatable :: locx(:,:) + integer(psb_i2pk_), intent(in) :: globx(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + + + ! locals + integer(psb_mpk_) :: ictxt, np, me, iroot, icomm, myrank, rootrank, iam, nlr + integer(psb_ipk_) :: ierr(5), err_act, nrow,& + & ilocx, jlocx, lda_locx, lda_globx, lock, globk, k, maxk, & + & col,pos + integer(psb_lpk_) :: m, n, i, j, idx, iglobx, jglobx + integer(psb_i2pk_),allocatable :: scatterv(:) + integer(psb_mpk_), allocatable :: displ(:), all_dim(:) + integer(psb_lpk_), allocatable :: l_t_g_all(:), ltg(:) + character(len=20) :: name, ch_err + + name='psb_scatterm' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + ! check on blacs grid + call psb_info(ictxt, iam, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(root)) then + iroot = root + if((iroot < -1).or.(iroot >= np)) then + info=psb_err_input_value_invalid_i_ + ierr(1)=5; ierr(2)=iroot + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + else + iroot = psb_root_ + end if + + iglobx = 1 + jglobx = 1 + lda_globx = size(globx,1) + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + icomm = psb_get_mpi_comm(ictxt) + myrank = psb_get_mpi_rank(ictxt,me) + + if (iroot==-1) then + lda_globx = size(globx, 1) + k = size(globx,2) + else + if (iam==iroot) then + k = size(globx,2) + lda_globx = size(globx, 1) + end if + end if + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + + + ! there should be a global check on k here!!! + if ((iroot==-1).or.(iam==iroot)) & + & call psb_chkglobvect(m,n,lda_globx,iglobx,jglobx,desc_a,info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_chk(glob)vect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + nrow=desc_a%get_local_rows() + ! root has to gather size information + allocate(displ(np),all_dim(np),ltg(nrow),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='Allocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + do i=1, nrow + ltg(i) = i + end do + call psb_loc_to_glob(ltg(1:nrow),desc_a,info) + + call psb_geall(locx,desc_a,info,n=k) + + if ((iroot == -1).or.(np == 1)) then + ! extract my chunk + do j=1,k + do i=1, nrow + locx(i,j)=globx(ltg(i),j) + end do + end do + else + + rootrank = psb_get_mpi_rank(ictxt,iroot) + ! + ! This is potentially unsafe when IPK=8 + ! But then, IPK=8 is highly experimental anyway. + ! + nlr = nrow + call mpi_gather(nlr,1,psb_mpi_mpk_,all_dim,& + & 1,psb_mpi_mpk_,rootrank,icomm,info) + + if (iam == iroot) then + displ(1)=0 + do i=2,np + displ(i)=displ(i-1)+all_dim(i-1) + end do + + ! root has to gather loc_glob from each process + allocate(l_t_g_all(sum(all_dim)),scatterv(sum(all_dim)),stat=info) + else + ! + ! This is to keep debugging compilers from being upset by + ! calling an external MPI function with an unallocated array; + ! the Fortran side would complain even if the MPI side does + ! not use the unallocated stuff. + ! + allocate(l_t_g_all(1),scatterv(1),stat=info) + end if + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='Allocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + call mpi_gatherv(ltg,nlr,& + & psb_mpi_lpk_,l_t_g_all,all_dim,& + & displ,psb_mpi_lpk_,rootrank,icomm,info) + + do col=1, k + ! prepare vector to scatter + if(iam == iroot) then + do i=1,np + pos=displ(i) + do j=1, all_dim(i) + idx=l_t_g_all(pos+j) + scatterv(pos+j)=globx(idx,col) + end do + end do + end if + + ! scatter + call mpi_scatterv(scatterv,all_dim,displ,& + & psb_mpi_i2pk_,locx(1,col),nrow,& + & psb_mpi_i2pk_,rootrank,icomm,info) + + end do + + deallocate(l_t_g_all, scatterv,stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='deallocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + end if + deallocate(all_dim, displ, ltg,stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='deallocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return + +end subroutine psb_i2scatterm + + + + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ + +! Subroutine: psb_i2scatterv +! This subroutine scatters a global vector locally owned by one process +! into pieces that are local to all the processes. +! +! Arguments: +! globx - integer,dimension(:). The global vector to scatter. +! locx - integer,dimension(:). The local piece of the ditributed vector. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +! iroot - integer(optional). The process that owns the global vector. If -1 all +! the processes have a copy. +! +subroutine psb_i2scatterv(globx, locx, desc_a, info, root) + use psb_base_mod, psb_protect_name => psb_i2scatterv +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + + integer(psb_i2pk_), intent(out), allocatable :: locx(:) + integer(psb_i2pk_), intent(in) :: globx(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + + + ! locals + integer(psb_mpk_) :: ictxt, np, iam, iroot, iiroot, icomm, myrank, rootrank, nlr + integer(psb_ipk_) :: ierr(5), err_act, nrow,& + & ilocx, jlocx, lda_locx, lda_globx, k, pos, ilx, jlx + integer(psb_lpk_) :: m, n, i, j, idx, iglobx, jglobx + integer(psb_i2pk_), allocatable :: scatterv(:) + integer(psb_mpk_), allocatable :: displ(:), all_dim(:) + integer(psb_lpk_), allocatable :: l_t_g_all(:), ltg(:) + character(len=20) :: name, ch_err + integer(psb_ipk_) :: debug_level, debug_unit + + name='psb_scatterv' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + ictxt=desc_a%get_context() + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + + ! check on blacs grid + call psb_info(ictxt, iam, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(root)) then + iroot = root + if((iroot < -1).or.(iroot > np)) then + info=psb_err_input_value_invalid_i_ + ierr(1) = 5; ierr(2)=iroot + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + else + iroot = psb_root_ + end if + + icomm = psb_get_mpi_comm(ictxt) + myrank = psb_get_mpi_rank(ictxt,iam) + + iglobx = 1 + jglobx = 1 + ilocx = 1 + jlocx = 1 + if ((iroot==-1).or.(iam==iroot))& + & lda_globx = size(globx, 1) + + + m = desc_a%get_global_rows() + n = desc_a%get_global_cols() + + k = 1 + ! there should be a global check on k here!!! + if ((iroot==-1).or.(iam==iroot)) & + & call psb_chkglobvect(m,n,lda_globx,iglobx,jglobx,desc_a,info) + + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_chk(glob)vect' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + nrow = desc_a%get_local_rows() + allocate(displ(np),all_dim(np),ltg(nrow),stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='Allocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + do i=1, nrow + ltg(i) = i + end do + call psb_loc_to_glob(ltg(1:nrow),desc_a,info) + call psb_geall(locx,desc_a,info) + + if ((iroot == -1).or.(np == 1)) then + ! extract my chunk + do i=1, nrow + locx(i)=globx(ltg(i)) + end do + else + rootrank = psb_get_mpi_rank(ictxt,iroot) + ! + ! This is potentially unsafe when IPK=8 + ! But then, IPK=8 is highly experimental anyway. + ! + nlr = nrow + call mpi_gather(nlr,1,psb_mpi_mpk_,all_dim,& + & 1,psb_mpi_mpk_,rootrank,icomm,info) + + if(iam == iroot) then + displ(1)=0 + do i=2,np + displ(i)=displ(i-1) + all_dim(i-1) + end do + if (debug_level >= psb_debug_inner_) then + write(debug_unit,*) iam,' ',trim(name),' displ:',displ(1:np), & + &' dim',all_dim(1:np), sum(all_dim) + endif + + ! root has to gather loc_glob from each process + allocate(l_t_g_all(sum(all_dim)),scatterv(sum(all_dim)),stat=info) + + else + ! + ! This is to keep debugging compilers from being upset by + ! calling an external MPI function with an unallocated array; + ! the Fortran side would complain even if the MPI side does + ! not use the unallocated stuff. + ! + allocate(l_t_g_all(1),scatterv(1),stat=info) + end if + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='Allocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + call mpi_gatherv(ltg,nlr,& + & psb_mpi_lpk_,l_t_g_all,all_dim,& + & displ,psb_mpi_lpk_,rootrank,icomm,info) + + ! prepare vector to scatter + if (iam == iroot) then + do i=1,np + pos=displ(i) + do j=1, all_dim(i) + idx=l_t_g_all(pos+j) + scatterv(pos+j)=globx(idx) + + end do + end do + end if + + call mpi_scatterv(scatterv,all_dim,displ,& + & psb_mpi_i2pk_,locx,nrow,& + & psb_mpi_i2pk_,rootrank,icomm,info) + + deallocate(l_t_g_all, scatterv,stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='deallocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + + deallocate(all_dim, displ, ltg,stat=info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='deallocate' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ione*ictxt,err_act) + + return + +end subroutine psb_i2scatterv + diff --git a/base/comm/psb_ispgather.F90 b/base/comm/psb_ispgather.F90 index d13c2e7cd..622641cbf 100644 --- a/base/comm/psb_ispgather.F90 +++ b/base/comm/psb_ispgather.F90 @@ -70,7 +70,7 @@ subroutine psb_isp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_isp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_isp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_ipk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_isp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_ipk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_@LX@sp_allgather subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_ipk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_ipk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_ipk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/comm/psb_lspgather.F90 b/base/comm/psb_lspgather.F90 index 2f5881168..bfba8a974 100644 --- a/base/comm/psb_lspgather.F90 +++ b/base/comm/psb_lspgather.F90 @@ -70,7 +70,7 @@ subroutine psb_lsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_lsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_lsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_lsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_@LX@sp_allgather subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_lpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_@LX@@LX@sp_allgather(globa, loca, desc_a, info, root, dupl,keepn end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/comm/psb_sspgather.F90 b/base/comm/psb_sspgather.F90 index 7123a9887..e25c11451 100644 --- a/base/comm/psb_sspgather.F90 +++ b/base/comm/psb_sspgather.F90 @@ -70,7 +70,7 @@ subroutine psb_ssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_ssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_ssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_ssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_lssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_lssp_allgather subroutine psb_lslssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_lslssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_lslssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_lslssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_r_spk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_r_spk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_r_spk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_lslssp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/comm/psb_zspgather.F90 b/base/comm/psb_zspgather.F90 index f4a27681c..62a4c186e 100644 --- a/base/comm/psb_zspgather.F90 +++ b/base/comm/psb_zspgather.F90 @@ -70,7 +70,7 @@ subroutine psb_zsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: locia(:), locja(:), glbia(:), glbja(:) integer(psb_ipk_) :: ierr(5) @@ -98,7 +98,12 @@ subroutine psb_zsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -137,27 +142,48 @@ subroutine psb_zsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep call psb_errpush(info,name); goto 9999 end if #endif + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call psb_realloc(nzg,glbia,info) + if (info == psb_success_) call psb_realloc(nzg,glbja,info) + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call psb_realloc(ione,glbia,info) + if (info == psb_success_) call psb_realloc(ione,glbja,info) + if (info == psb_success_) call glob_coo%allocate(ione,ione,ione) + end if - if (info == psb_success_) call psb_realloc(nzg,glbia,info) - if (info == psb_success_) call psb_realloc(nzg,glbja,info) - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& - & glbia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& - & glbja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locia,ndx,psb_mpi_lpk_,& + & glbia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(locja,ndx,psb_mpi_lpk_,& + & glbja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + + end if if (minfo /= psb_success_) then info = minfo @@ -172,11 +198,13 @@ subroutine psb_zsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keep ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - glob_coo%ia(1:nzg) = glbia(1:nzg) - glob_coo%ja(1:nzg) = glbja(1:nzg) - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + glob_coo%ia(1:nzg) = glbia(1:nzg) + glob_coo%ja(1:nzg) = glbja(1:nzg) + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if deallocate(glbia,glbja, stat=info) else @@ -228,7 +256,7 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee integer(psb_ipk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -256,7 +284,13 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -269,7 +303,7 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee goto 9999 end if - + if (keeploc_) then call loca%cp_to(loc_coo) else @@ -294,7 +328,11 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 ! ! PLS REVIEW AND ADD OVERFLOW ERROR CHECKING @@ -303,24 +341,37 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') goto 9999 - end if + end if call loc_coo%free() ! ! Is the code below safe? For very large cases @@ -328,9 +379,11 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee ! for very large cases it does not make sense to ! gather the matrix on a single procecss anyway... ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ @@ -346,7 +399,7 @@ subroutine psb_lzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,kee call psb_error_handler(ione*ictxt,err_act) return - + end subroutine psb_lzsp_allgather subroutine psb_lzlzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,keeploc) @@ -378,7 +431,7 @@ subroutine psb_lzlzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k integer(psb_lpk_) :: ip,naggrm1,naggrp1, i, j, k, nzl logical :: keepnum_, keeploc_ integer(psb_mpk_) :: ictxt,np,me - integer(psb_mpk_) :: icomm, minfo, ndx + integer(psb_mpk_) :: icomm, minfo, ndx, root_ integer(psb_mpk_), allocatable :: nzbr(:), idisp(:) integer(psb_lpk_), allocatable :: lnzbr(:) integer(psb_ipk_) :: ierr(5) @@ -406,7 +459,13 @@ subroutine psb_lzlzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k else keeploc_ = .true. end if - call globa%free() + if (present(root)) then + root_ = root + else + root_ = -1 + end if + + if ((root_ == -1).or.(root_ == me)) call globa%free() if (keepnum_) then nrg = desc_a%get_global_rows() @@ -444,25 +503,43 @@ subroutine psb_lzlzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k call psb_errpush(info,name); goto 9999 end if #endif - if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + if ((root_ == -1).or.(root_ == me)) then + if (info == psb_success_) call glob_coo%allocate(nrg,ncg,nzg) + else + if (info == psb_success_) call glob_coo%allocate(1_psb_lpk_,1_psb_lpk_,1_psb_lpk_) + end if if (info /= psb_success_) goto 9999 do ip=1,np idisp(ip) = sum(nzbr(1:ip-1)) enddo - ndx = nzbr(me+1) - call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& - & glob_coo%val,nzbr,idisp,& - & psb_mpi_c_dpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& - & glob_coo%ia,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - if (minfo == psb_success_) call & - & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& - & glob_coo%ja,nzbr,idisp,& - & psb_mpi_lpk_,icomm,minfo) - + ndx = nzbr(me+1) + + if (root_ == -1) then + call mpi_allgatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_allgatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,icomm,minfo) + else + call mpi_gatherv(loc_coo%val,ndx,psb_mpi_c_dpk_,& + & glob_coo%val,nzbr,idisp,& + & psb_mpi_c_dpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ia,ndx,psb_mpi_lpk_,& + & glob_coo%ia,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + if (minfo == psb_success_) call & + & mpi_gatherv(loc_coo%ja,ndx,psb_mpi_lpk_,& + & glob_coo%ja,nzbr,idisp,& + & psb_mpi_lpk_,root_,icomm,minfo) + end if if (minfo /= psb_success_) then info = minfo call psb_errpush(psb_err_internal_error_,name,a_err=' from mpi_allgatherv') @@ -470,9 +547,11 @@ subroutine psb_lzlzsp_allgather(globa, loca, desc_a, info, root, dupl,keepnum,k end if call loc_coo%free() ! - call glob_coo%set_nzeros(nzg) - if (present(dupl)) call glob_coo%set_dupl(dupl) - call globa%mv_from(glob_coo) + if ((root_ == -1).or.(root_ == me)) then + call glob_coo%set_nzeros(nzg) + if (present(dupl)) call glob_coo%set_dupl(dupl) + call globa%mv_from(glob_coo) + end if else write(psb_err_unit,*) 'SP_ALLGATHER: Not implemented yet with keepnum ',keepnum_ diff --git a/base/internals/psi_a2a_fnd_owner.F90 b/base/internals/psi_a2a_fnd_owner.F90 index 52e8b0ae9..b9cd9bb25 100644 --- a/base/internals/psi_a2a_fnd_owner.F90 +++ b/base/internals/psi_a2a_fnd_owner.F90 @@ -47,7 +47,7 @@ ! so it goes for an all-to-all by building an auxiliary neighbours list and ! reusing the neighbour version. ! -subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info) +subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info,samesize) use psb_serial_mod use psb_const_mod use psb_error_mod @@ -66,15 +66,22 @@ subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info) integer(psb_ipk_), allocatable, intent(out) :: iprc(:) class(psb_indx_map), intent(in) :: idxmap integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: samesize integer(psb_ipk_), allocatable :: tmpadj(:) - integer(psb_mpk_) :: icomm, minfo, iictxt - integer(psb_ipk_) :: i,n_row,n_col,err_act,nv + integer(psb_lpk_), allocatable :: rmtidx(:) + integer(psb_ipk_), allocatable :: tproc(:), lclidx(:) + integer(psb_mpk_), allocatable :: hsz(:),hidx(:), sdidx(:), rvidx(:),& + & sdsz(:), rvsz(:), sdhd(:), rvhd(:), p2pstat(:,:) + integer(psb_mpk_) :: icomm, minfo, iictxt,nv + integer(psb_ipk_) :: i,n_row,n_col,err_act,gsz integer(psb_lpk_) :: mglob, ih integer(psb_ipk_) :: ictxt,np,me, nresp - real(psb_dpk_) :: t0, t1, t2, t3, t4, tamx, tidx - character(len=20) :: name + logical, parameter :: use_psi_adj=.true. + real(psb_dpk_) :: t0, t1, t2, t3, t4, tamx, tidx + character(len=20) :: name + logical :: samesize_ info = psb_success_ name = 'psi_a2a_fnd_owner' @@ -100,15 +107,95 @@ subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info) goto 9999 end if - ! - ! Reuse the adjcncy version by tricking it with an adjcncy list - ! that contains everybody but ME. - ! + if (present(samesize)) then + samesize_ = samesize + else + samesize_ = .false. + end if nv = size(idx) - call psb_realloc(np-1,tmpadj,info) - tmpadj(1:me) = [(i,i=0,me-1)] - tmpadj(me+1:np-1) = [(i,i=me+1,np-1)] - call psi_adjcncy_fnd_owner(idx,iprc,tmpadj,idxmap,info) + ! write(0,*) me,name,' :',use_psi_adj,samesize_,nv + if (use_psi_adj) then + ! + ! Reuse the adjcncy version by tricking it with an adjcncy list + ! that contains everybody but ME. + ! + call psb_realloc(np-1,tmpadj,info) + tmpadj(1:me) = [(i,i=0,me-1)] + tmpadj(me+1:np-1) = [(i,i=me+1,np-1)] + call psi_adjcncy_fnd_owner(idx,iprc,tmpadj,idxmap,info) + + else + if (samesize_) then + ! + ! Variant when IDX is guaranteed to have the same size on all + ! processes. To be tested for performance: is it worth it? + ! Probably yes. + ! + gsz = nv*np + Allocate(rmtidx(gsz),lclidx(gsz),iprc(nv),stat=info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Allocate') + goto 9999 + end if + call mpi_allgather(idx,nv,psb_mpi_lpk_,rmtidx,nv,psb_mpi_lpk_,icomm,minfo) + call idxmap%g2l(rmtidx(1:gsz),lclidx(1:gsz),info,owned=.true.) + ! + ! Reuse lclidx to encode owning process + ! + do i=1, gsz + if ((1<=lclidx(i)).and.(lclidx(i)<=n_row)) then + lclidx(i) = me + else + lclidx(i) = -1 + end if + end do + call mpi_reduce_scatter_block(lclidx,iprc,nv,psb_mpi_ipk_,mpi_max,icomm,minfo) + + else + ! + ! 1. allgetherv + ! 2. local conversion + ! 3. reduce_scatter + ! + ! + ! The basic idea is very simple. + ! First we collect (to all) all the requests. + Allocate(hidx(np+1),hsz(np),stat=info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Allocate') + goto 9999 + end if + + call mpi_allgather(nv,1,psb_mpi_mpk_,hsz,1,psb_mpi_mpk_,icomm,minfo) + hidx(1) = 0 + do i=1, np + hidx(i+1) = hidx(i) + hsz(i) + end do + gsz = hidx(np+1) + Allocate(rmtidx(gsz),lclidx(gsz),iprc(nv),stat=info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Allocate') + goto 9999 + end if + + call mpi_allgatherv(idx,hsz(me+1),psb_mpi_lpk_,& + & rmtidx,hsz,hidx,psb_mpi_lpk_,& + & icomm,minfo) + + call idxmap%g2l(rmtidx(1:gsz),lclidx(1:gsz),info,owned=.true.) + ! + ! Reuse lclidx to encode owning process + ! + do i=1, gsz + if ((1<=lclidx(i)).and.(lclidx(i)<=n_row)) then + lclidx(i) = me + else + lclidx(i) = -1 + end if + end do + call mpi_reduce_scatter(lclidx,iprc,hsz,psb_mpi_ipk_,mpi_max,icomm,minfo) + end if + end if call psb_erractionrestore(err_act) return diff --git a/base/internals/psi_adjcncy_fnd_owner.F90 b/base/internals/psi_adjcncy_fnd_owner.F90 index ed2445544..f26bb38fa 100644 --- a/base/internals/psi_adjcncy_fnd_owner.F90 +++ b/base/internals/psi_adjcncy_fnd_owner.F90 @@ -59,6 +59,7 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) use psb_error_mod use psb_penv_mod use psb_realloc_mod + use psb_timers_mod use psb_indx_map_mod, psb_protect_name => psi_adjcncy_fnd_owner #ifdef MPI_MOD use mpi @@ -85,10 +86,11 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) & last_ih, last_j, nidx, nrecv, nadj integer(psb_lpk_) :: mglob, ih integer(psb_ipk_) :: ictxt,np,me - logical, parameter :: gettime=.false., debug=.false. - logical, parameter :: a2av_impl=.true. - logical, parameter :: mpi_irecv_impl=.false. - logical, parameter :: psb_rcv_impl=.false. + logical, parameter :: gettime=.true., debug=.false. + integer(psb_mpk_) :: xchg_alg + logical, parameter :: do_timings=.false. + integer(psb_ipk_), save :: idx_phase1=-1, idx_phase2=-1, idx_phase3=-1 + integer(psb_ipk_), save :: idx_phase11=-1, idx_phase12=-1, idx_phase13=-1 real(psb_dpk_) :: t0, t1, t2, t3, t4, tamx, tidx character(len=20) :: name @@ -102,6 +104,19 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) n_row = idxmap%get_lr() n_col = idxmap%get_lc() iictxt = ictxt + if ((do_timings).and.(idx_phase1==-1)) & + & idx_phase1 = psb_get_timer_idx("ADJ_FND_OWN: phase1 ") + if ((do_timings).and.(idx_phase2==-1)) & + & idx_phase2 = psb_get_timer_idx("ADJ_FND_OWN: phase2") + if ((do_timings).and.(idx_phase3==-1)) & + & idx_phase3 = psb_get_timer_idx("ADJ_FND_OWN: phase3") + if ((do_timings).and.(idx_phase11==-1)) & + & idx_phase11 = psb_get_timer_idx("ADJ_FND_OWN: phase11 ") + if ((do_timings).and.(idx_phase12==-1)) & + & idx_phase12 = psb_get_timer_idx("ADJ_FND_OWN: phase12") + if ((do_timings).and.(idx_phase13==-1)) & + & idx_phase13 = psb_get_timer_idx("ADJ_FND_OWN: phase13") + call psb_info(ictxt, me, np) @@ -129,8 +144,11 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) end if iprc = -1 ! write(0,*) me,name,' Going through ',nidx,nadj + xchg_alg = psi_get_adj_alg() + select case(xchg_alg) + case(psi_adj_fnd_a2av_) + if (do_timings) call psb_tic(idx_phase1) - if (a2av_impl) then ! ! First simple minded version with auxiliary arrays ! dimensioned on NP. @@ -146,6 +164,7 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) ! ! First, send sizes according to adjcncy list ! + if (do_timings) call psb_tic(idx_phase11) sdsz = 0 do j=1, nadj sdsz(adj(j)) = nidx @@ -154,15 +173,20 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& & rvsz,1,psb_mpi_mpk_,icomm,minfo) + if (do_timings) call psb_toc(idx_phase11) + if (do_timings) call psb_tic(idx_phase12) rvidx(0) = 0 do i=0, np-1 rvidx(i+1) = rvidx(i) + rvsz(i) end do hsize = rvidx(np) + ! write(0,*)me,' Check on sizes from a2a:',hsize,rvsz(:) ! ! Second, allocate buffers and exchange data ! + if (do_timings) call psb_toc(idx_phase12) + if (do_timings) call psb_tic(idx_phase13) Allocate(rmtidx(hsize),lclidx(max(hsize,nidx*nadj)),& & tproc(max(hsize,nidx)),stat=info) @@ -173,7 +197,9 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) call mpi_alltoallv(idx,sdsz,sdidx,psb_mpi_lpk_,& & rmtidx,rvsz,rvidx,psb_mpi_lpk_,icomm,iret) - + if (do_timings) call psb_toc(idx_phase13) + if (do_timings) call psb_toc(idx_phase1) + if (do_timings) call psb_tic(idx_phase2) ! ! Third, compute local answers ! @@ -182,6 +208,8 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) tproc(i) = -1 if ((0 < lclidx(i)).and. (lclidx(i) <= n_row)) tproc(i) = me end do + if (do_timings) call psb_toc(idx_phase2) + if (do_timings) call psb_tic(idx_phase3) ! ! Fourth, exchange the answers @@ -203,10 +231,13 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) iprc(1:nidx) = max(iprc(1:nidx), lclidx(sdidx(i)+1:sdidx(i)+sdsz(i))) end if end do + if (do_timings) call psb_toc(idx_phase3) if (debug) write(0,*) me,' End of adjcncy_fnd ',iprc(1:nidx) - else if (mpi_irecv_impl) then + case(psi_adj_fnd_irecv_) + + if (do_timings) call psb_tic(idx_phase1) ! ! First simple minded version with auxiliary arrays ! dimensioned on NP. @@ -216,6 +247,7 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) Allocate(hidx(0:np),hsz(np),sdsz(0:np-1),rvsz(0:np-1),& & sdhd(0:np-1), rvhd(0:np-1), p2pstat(mpi_status_size,0:np-1),& & stat=info) + if (do_timings) call psb_tic(idx_phase11) sdhd(:) = mpi_request_null rvhd(:) = mpi_request_null ! @@ -255,6 +287,8 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) & p2ptag, icomm,rvhd(i),iret) end if end do + if (do_timings) call psb_toc(idx_phase11) + if (do_timings) call psb_tic(idx_phase12) do j=1, nadj if (nidx > 0) then prc = psb_get_mpi_rank(ictxt,adj(j)) @@ -265,7 +299,12 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) & p2ptag, icomm,iret) end if end do + if (do_timings) call psb_toc(idx_phase12) + if (do_timings) call psb_tic(idx_phase13) call mpi_waitall(np,rvhd,p2pstat,iret) + if (do_timings) call psb_toc(idx_phase13) + if (do_timings) call psb_toc(idx_phase1) + if (do_timings) call psb_tic(idx_phase2) ! ! Third, compute local answers @@ -275,6 +314,8 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) tproc(i) = -1 if ((0 < lclidx(i)).and. (lclidx(i) <= n_row)) tproc(i) = me end do + if (do_timings) call psb_toc(idx_phase2) + if (do_timings) call psb_tic(idx_phase3) ! ! At this point we can reuse lclidx to receive messages ! @@ -312,9 +353,10 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) do j = 1, nadj iprc(1:nidx) = max(iprc(1:nidx), lclidx((j-1)*nidx+1:(j-1)*nidx+nidx)) end do + if (do_timings) call psb_toc(idx_phase3) if (debug) write(0,*) me,' End of adjcncy_fnd ',iprc(1:nidx) - else if (psb_rcv_impl) then + case(psi_adj_fnd_pbrcv_) Allocate(hidx(0:np),hsz(np),& & sdsz(0:np-1),rvsz(0:np-1),stat=info) @@ -382,11 +424,11 @@ subroutine psi_adjcncy_fnd_owner(idx,iprc,adj,idxmap,info) if (nidx > 0) call psb_rcv(ictxt,tproc(1:nidx),adj(j)) iprc(1:nidx) = max(iprc(1:nidx), tproc(1:nidx)) end do - else + case default info = psb_err_internal_error_ call psb_errpush(info,name,a_err='invalid exchange alg choice') goto 9999 - end if + end select call psb_erractionrestore(err_act) return diff --git a/base/internals/psi_crea_index.f90 b/base/internals/psi_crea_index.f90 index ec7838990..126d54e2e 100644 --- a/base/internals/psi_crea_index.f90 +++ b/base/internals/psi_crea_index.f90 @@ -54,6 +54,7 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) use psb_desc_mod use psb_error_mod use psb_penv_mod + use psb_timers_mod use psi_mod, psb_protect_name => psi_i_crea_index implicit none @@ -69,6 +70,9 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) integer(psb_ipk_),parameter :: root=psb_root_,no_comm=-1 integer(psb_ipk_) :: debug_level, debug_unit character(len=20) :: name + logical, parameter :: do_timings=.false. + integer(psb_ipk_), save :: idx_phase1=-1, idx_phase2=-1, idx_phase3=-1 + integer(psb_ipk_), save :: idx_phase11=-1, idx_phase12=-1, idx_phase13=-1 info = psb_success_ name='psi_crea_index' @@ -84,12 +88,26 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) call psb_errpush(info,name) goto 9999 endif + if ((do_timings).and.(idx_phase1==-1)) & + & idx_phase1 = psb_get_timer_idx("PSI_CREA_INDEX: phase1 ") + if ((do_timings).and.(idx_phase2==-1)) & + & idx_phase2 = psb_get_timer_idx("PSI_CREA_INDEX: phase2") + if ((do_timings).and.(idx_phase3==-1)) & + & idx_phase3 = psb_get_timer_idx("PSI_CREA_INDEX: phase3") +!!$ if ((do_timings).and.(idx_phase11==-1)) & +!!$ & idx_phase11 = psb_get_timer_idx("PSI_CREA_INDEX: phase11 ") +!!$ if ((do_timings).and.(idx_phase12==-1)) & +!!$ & idx_phase12 = psb_get_timer_idx("PSI_CREA_INDEX: phase12") +!!$ if ((do_timings).and.(idx_phase13==-1)) & +!!$ & idx_phase13 = psb_get_timer_idx("PSI_CREA_INDEX: phase13") + ! ...extract dependence list (ordered list of identifer process ! which every process must communcate with... if (debug_level >= psb_debug_inner_) & & write(debug_unit,*) me,' ',trim(name),': calling extract_dep_list' mode = 1 + if (do_timings) call psb_tic(idx_phase1) call psi_extract_dep_list(ictxt,& & desc_a%is_bld(), desc_a%is_upd(),& @@ -105,6 +123,8 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) ! ...now process root contains dependence list of all processes... if (debug_level >= psb_debug_inner_) & & write(debug_unit,*) me,' ',trim(name),': root sorting dep list' + if (do_timings) call psb_toc(idx_phase1) + if (do_timings) call psb_tic(idx_phase2) call psi_dl_check(dep_list,dl_lda,np,length_dl) @@ -114,6 +134,8 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) call psb_errpush(psb_err_from_subroutine_,name,a_err='psi_sort_dl') goto 9999 end if + if (do_timings) call psb_toc(idx_phase2) + if (do_timings) call psb_tic(idx_phase3) if(debug_level >= psb_debug_inner_)& & write(debug_unit,*) me,' ',trim(name),': calling psi_desc_index' @@ -128,6 +150,7 @@ subroutine psi_i_crea_index(desc_a,index_in,index_out,nxch,nsnd,nrcv,info) call psb_errpush(psb_err_from_subroutine_,name,a_err='psi_desc_index') goto 9999 end if + if (do_timings) call psb_toc(idx_phase3) deallocate(dep_list,length_dl) if(debug_level >= psb_debug_inner_) & diff --git a/base/internals/psi_desc_impl.f90 b/base/internals/psi_desc_impl.f90 index b552a8ad4..43eae7bbb 100644 --- a/base/internals/psi_desc_impl.f90 +++ b/base/internals/psi_desc_impl.f90 @@ -63,6 +63,7 @@ end subroutine psi_renum_index subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) use psi_mod, psi_protect_name => psi_i_cnv_dsc + use psb_timers_mod use psb_realloc_mod implicit none @@ -82,6 +83,9 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) integer(psb_ipk_) :: debug_level, debug_unit logical, parameter :: debug=.false. character(len=20) :: name + logical, parameter :: do_timings=.false. + integer(psb_ipk_), save :: idx_phase1=-1, idx_phase2=-1, idx_phase3=-1 + integer(psb_ipk_), save :: idx_phase11=-1, idx_phase12=-1, idx_phase13=-1 name='psi_cnv_desc' call psb_get_erraction(err_act) @@ -97,8 +101,23 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) call psb_errpush(info,name) goto 9999 endif + if ((do_timings).and.(idx_phase1==-1)) & + & idx_phase1 = psb_get_timer_idx("PSI_CNV_DSC: phase1 ") + if ((do_timings).and.(idx_phase2==-1)) & + & idx_phase2 = psb_get_timer_idx("PSI_CNV_DSC: phase2") + if ((do_timings).and.(idx_phase3==-1)) & + & idx_phase3 = psb_get_timer_idx("PSI_CNV_DSC: phase3") + if ((do_timings).and.(idx_phase11==-1)) & + & idx_phase11 = psb_get_timer_idx("PSI_CNV_DSC: phase11 ") + if ((do_timings).and.(idx_phase12==-1)) & + & idx_phase12 = psb_get_timer_idx("PSI_CNV_DSC: phase12") + if ((do_timings).and.(idx_phase13==-1)) & + & idx_phase13 = psb_get_timer_idx("PSI_CNV_DSC: phase13") + if (do_timings) call psb_tic(idx_phase1) + if (do_timings) call psb_tic(idx_phase11) + ! first the halo index if (debug_level>0) write(debug_unit,*) me,'Calling crea_index on halo',& & size(halo_in) @@ -111,6 +130,8 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) if (debug_level>0) write(debug_unit,*) me,'Done crea_index on halo' if (debug_level>0) write(debug_unit,*) me,'Calling crea_index on ext' + if (do_timings) call psb_toc(idx_phase11) + if (do_timings) call psb_tic(idx_phase12) ! then ext index @@ -124,6 +145,8 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) if (debug_level>0) write(debug_unit,*) me,'Done crea_index on ext' if (debug_level>0) write(debug_unit,*) me,'Calling crea_index on ovrlap' + if (do_timings) call psb_toc(idx_phase12) + if (do_timings) call psb_tic(idx_phase13) ! then the overlap index call psi_crea_index(cdesc,ovrlap_in, idx_out,nxch,nsnd,nrcv,info) @@ -136,6 +159,9 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) call psb_errpush(psb_err_from_subroutine_,name,a_err='psb_move_alloc') goto 9999 end if + if (do_timings) call psb_toc(idx_phase13) + if (do_timings) call psb_toc(idx_phase1) + if (do_timings) call psb_tic(idx_phase2) ! next ovrlap_elem @@ -161,6 +187,8 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) call psb_errpush(psb_err_from_subroutine_,name,a_err='psb_move_alloc') goto 9999 end if + if (do_timings) call psb_toc(idx_phase2) + if (do_timings) call psb_tic(idx_phase3) ! finally bnd_elem call psi_crea_bnd_elem(idx_out,cdesc,info) @@ -177,7 +205,8 @@ subroutine psi_i_cnv_dsc(halo_in,ovrlap_in,ext_in,cdesc, info, mold) goto 9999 end if if (debug_level>0) write(debug_unit,*) me,'Done crea_bnd_elem' - + if (do_timings) call psb_toc(idx_phase3) + call psb_erractionrestore(err_act) return diff --git a/base/internals/psi_desc_index.F90 b/base/internals/psi_desc_index.F90 index 7f36c6ea5..f23662f16 100644 --- a/base/internals/psi_desc_index.F90 +++ b/base/internals/psi_desc_index.F90 @@ -128,11 +128,15 @@ subroutine psi_i_desc_index(desc,index_in,dep_list,& integer(psb_mpk_),allocatable :: brvindx(:),rvsz(:),& & bsdindx(:),sdsz(:) + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size),& + & iret, sz + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:) + integer(psb_ipk_) :: ihinsz,ntot,k,err_act,nidx,& - & idxr, idxs, iszs, iszr, nesd, nerv + & idxr, idxs, iszs, iszr, nesd, nerv, ixp, idx integer(psb_mpk_) :: icomm, minfo - logical,parameter :: usempi=.true. + logical, parameter :: usempi=.false. integer(psb_ipk_) :: debug_level, debug_unit character(len=20) :: name @@ -255,12 +259,12 @@ subroutine psi_i_desc_index(desc,index_in,dep_list,& call desc%indxmap%l2g(index_in(i+1:i+nerv),& & sndbuf(bsdindx(proc+1)+1:bsdindx(proc+1)+nerv),& & info) - + if (info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='l2g') goto 9999 end if - + bsdindx(proc+1) = bsdindx(proc+1) + nerv i = i + nerv + 1 end do @@ -282,11 +286,76 @@ subroutine psi_i_desc_index(desc,index_in,dep_list,& idxr = idxr + rvsz(proc+1) end do - call mpi_alltoallv(sndbuf,sdsz,bsdindx,psb_mpi_lpk_,& - & rcvbuf,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo /= psb_success_) then - call psb_errpush(psb_err_from_subroutine_,name,a_err='mpi_alltoallv') - goto 9999 + if (usempi) then + call mpi_alltoallv(sndbuf,sdsz,bsdindx,psb_mpi_lpk_,& + & rcvbuf,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='mpi_alltoallv') + goto 9999 + end if + else + if (.true.) then + allocate(prcid(length_dl),rvhd(length_dl)) + prcid = -1 + ixp = 1 + do i=1, length_dl + proc = dep_list(i) + prcid(ixp) = psb_get_mpi_rank(ictxt,proc) + sz = rvsz(proc+1) + if (sz > 0) then + p2ptag = psb_long_tag + idx = brvindx(proc+1) + call mpi_irecv(rcvbuf(idx+1:idx+sz),sz,& + & psb_mpi_lpk_, prcid(ixp), p2ptag, icomm,& + & rvhd(ixp),iret) + end if + ixp = ixp + 1 + end do + ixp = 1 + do i=1, length_dl + proc = dep_list(i) + prcid(ixp) = psb_get_mpi_rank(ictxt,proc) + sz = sdsz(proc+1) + if (sz > 0) then + p2ptag = psb_long_tag + idx = bsdindx(proc+1) + call mpi_send(sndbuf(idx+1:idx+sz),sz,& + & psb_mpi_lpk_, prcid(ixp), p2ptag, & + & icomm,iret) + end if + ixp = ixp + 1 + end do + ixp = 1 + do i=1, length_dl + proc = dep_list(i) + prcid(ixp) = psb_get_mpi_rank(ictxt,proc) + sz = rvsz(proc+1) + if (sz > 0) then + call mpi_wait(rvhd(ixp),p2pstat,iret) + end if + ixp = ixp + 1 + end do + else + + do i=1, length_dl + proc = dep_list(i) + sz = sdsz(proc+1) + idx = bsdindx(proc+1) + if (sz > 0) then + call psb_snd(ictxt,sndbuf(idx+1:idx+sz), proc) + end if + end do + + do i=1, length_dl + proc = dep_list(i) + sz = rvsz(proc+1) + idx = brvindx(proc+1) + if (sz > 0) then + call psb_rcv(ictxt,rcvbuf(idx+1:idx+sz),proc) + end if + end do + + end if end if ! @@ -327,7 +396,7 @@ subroutine psi_i_desc_index(desc,index_in,dep_list,& return 9999 call psb_error_handler(ictxt,err_act) - + return end subroutine psi_i_desc_index diff --git a/base/internals/psi_dl_check.f90 b/base/internals/psi_dl_check.f90 index 8b12f0239..bf25976bc 100644 --- a/base/internals/psi_dl_check.f90 +++ b/base/internals/psi_dl_check.f90 @@ -79,7 +79,7 @@ subroutine psi_i_dl_check(dep_list,dl_lda,np,length_dl) ! ...add proc to proc2 s dep_list.....',proc,proc2 length_dl(proc2) = length_dl(proc2)+1 if (length_dl(proc2) > size(dep_list,1)) then - write(psb_err_unit,*)'error in crea_halo', proc2,proc,& + write(psb_err_unit,*)'error in dl_check', proc2,proc,& & length_dl(proc2),'>',size(dep_list,1) endif dep_list(length_dl(proc2),proc2) = proc diff --git a/base/internals/psi_graph_fnd_owner.F90 b/base/internals/psi_graph_fnd_owner.F90 index 7e69c1ef9..b951945e5 100644 --- a/base/internals/psi_graph_fnd_owner.F90 +++ b/base/internals/psi_graph_fnd_owner.F90 @@ -101,13 +101,13 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) integer(psb_ipk_), allocatable :: tprc(:), tsmpl(:), ladj(:) integer(psb_mpk_) :: icomm, minfo, iictxt integer(psb_ipk_) :: i,n_row,n_col,err_act,ip,j,ipnt, nsampl_out,& - & nv, n_answers, n_rest, nsampl_in, locr_max, & - & nrest_max, nadj, maxspace, mxnsin + & nv, n_answers, nreqst, nsampl_in, locr_max, & + & nreqst_max, nadj, maxspace, mxnsin integer(psb_lpk_) :: mglob, ih integer(psb_ipk_) :: ictxt,np,me, nresp integer(psb_ipk_), parameter :: nt=4 integer(psb_ipk_) :: tmpv(4) - logical, parameter :: do_timings=.false., trace=.false. + logical, parameter :: do_timings=.false., trace=.false., debugsz=.false. integer(psb_ipk_), save :: idx_sweep0=-1, idx_loop_a2a=-1, idx_loop_neigh=-1 real(psb_dpk_) :: t0, t1, t2, t3, t4 character(len=20) :: name @@ -162,20 +162,25 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) ! call psb_safe_ab_cpy(idxmap%p_adjcncy,ladj,info) nadj = psb_size(ladj) - ! This makes ladj allocated with size 0 just in case + ! This makes ladj allocated with size 0 if needed, as opposed to unallocated call psb_realloc(nadj,ladj,info) - n_rest = nv - n_answers - nrest_max = n_rest + ! + ! Throughout the subroutine, nreqst is the number of local inquiries + ! that have not been answered yet + ! + nreqst = nv - n_answers + nreqst_max = nreqst ! ! Choice of maxspace should be adjusted to account for a default ! "sensible" size and/or a user-specified value ! tmpv(1) = nadj - tmpv(2) = nrest_max + tmpv(2) = nreqst_max tmpv(3) = n_row tmpv(4) = psb_cd_get_maxspace() call psb_max(ictxt,tmpv) + nreqst_max = tmpv(2) locr_max = tmpv(3) maxspace = nt*locr_max if (tmpv(4) > 0) maxspace = min(maxspace,tmpv(4)) @@ -187,18 +192,21 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) ! Do a preliminary run on the user-defined adjacency lists ! if (trace.and.(me == 0)) write(0,*) ' Initial sweep on user-defined topology' - nsampl_in = min(n_rest,max(1,(maxspace+max(1,nadj)-1))/(max(1,nadj))) + if (debugsz) write(0,*) me,' Initial sweep on user-defined topology',nreqst + nsampl_in = min(nreqst,max(1,(maxspace+max(1,nadj)-1))/(max(1,nadj))) call psi_adj_fnd_sweep(idx,iprc,ladj,idxmap,nsampl_in,n_answers) call idxmap%xtnd_p_adjcncy(ladj) - n_rest = nv - n_answers - nrest_max = n_rest - call psb_max(ictxt,nrest_max) - if (trace.and.(me == 0)) write(0,*) ' After initial sweep:',nrest_max + nreqst = nv - n_answers + nreqst_max = nreqst + call psb_max(ictxt,nreqst_max) + if (trace.and.(me == 0)) write(0,*) ' After initial sweep:',nreqst_max + if (debugsz) write(0,*) me,' After sweep on user-defined topology',nreqst_max end if if (do_timings) call psb_toc(idx_sweep0) - fnd_owner_loop: do while (nrest_max>0) - if (do_timings) call psb_tic(idx_loop_a2a) + fnd_owner_loop: do while (nreqst_max>0) + if (do_timings) call psb_tic(idx_loop_a2a) + if (debugsz) write(0,*) me,' fnd_owner_loop',nreqst_max ! ! The basic idea of this loop is to alternate between ! searching through all processes and searching @@ -207,28 +215,34 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) ! 1. Select a sample such that the total size is <= maxspace ! sample query is then sent to all processes ! - ! if (trace.and.(me == 0)) write(0,*) 'Looping in graph_fnd_owner: ', nrest_max - nsampl_in = min(n_rest,max(1,(maxspace+np-1)/np)) + ! if (trace.and.(me == 0)) write(0,*) 'Looping in graph_fnd_owner: ', nreqst_max + nsampl_in = psb_cd_get_samplesize() + nsampl_in = min(max(1,(maxspace+np-1)/np),nsampl_in) ! ! Choose a sample, should it be done in this simplistic way? ! Note: nsampl_in is a hint, not an absolute, hence nsampl_out ! ipnt = 1 -!!$ write(0,*) me,' Into first sampling ',nsampl_in - call psi_get_sample(ipnt, idx,iprc,tidx,tsmpl,nsampl_in,nsampl_out) + call psi_get_sample(ipnt, idx,iprc,tidx,tsmpl,nsampl_in,nsampl_out, pad=.true.) nsampl_in = min(nsampl_out,nsampl_in) -!!$ write(0,*) me,' From first sampling ',nsampl_in + if (debugsz) write(0,*) me,' From first sampling ',nsampl_in ! ! 2. Do a search on all processes; this is supposed to find ! the owning process for all inputs; ! - call psi_a2a_fnd_owner(tidx(1:nsampl_in),tprc,idxmap,info) + call psi_a2a_fnd_owner(tidx(1:nsampl_in),tprc,idxmap,info, samesize=.true.) + if (debugsz) write(0,*) me,' From a2a_fnd_owner ',info + ! + ! We might have padded when looking for owners, so the actual samples + ! could be less than they appear. Should be explained better. + ! + nsampl_in = min(nreqst,nsampl_in) call psi_cpy_out(iprc,tprc,tsmpl,nsampl_in,nsampl_out) if (nsampl_out /= nsampl_in) then write(0,*) me,'Warning: indices not found by a2a_fnd_owner ',nsampl_out,nsampl_in end if n_answers = n_answers + nsampl_out - n_rest = nv - n_answers + nreqst = nv - n_answers ! ! 3. Extract the resulting adjacency list and add it to the ! indxmap; @@ -245,18 +259,18 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) ! Need to set up a proper loop here to have a complete ! sweep over the input vector. Done inside adj_fnd_sweep. ! -!!$ write(0,*) me,' After a2a ',n_rest - nsampl_in = min(n_rest,max(1,(maxspace+max(1,nadj)-1))/(max(1,nadj))) +!!$ write(0,*) me,' After a2a ',nreqst + nsampl_in = min(nreqst,max(1,(maxspace+max(1,nadj)-1))/(max(1,nadj))) mxnsin = nsampl_in call psb_max(ictxt,mxnsin) !!$ write(0,*) me, ' mxnsin ',mxnsin if (mxnsin>0) call psi_adj_fnd_sweep(idx,iprc,ladj,idxmap,nsampl_in,n_answers) call idxmap%xtnd_p_adjcncy(ladj) - n_rest = nv - n_answers - nrest_max = n_rest - call psb_max(ictxt,nrest_max) - if (trace.and.(me == 0)) write(0,*) ' fnd_owner_loop remaining:',nrest_max + nreqst = nv - n_answers + nreqst_max = nreqst + call psb_max(ictxt,nreqst_max) + if (trace.and.(me == 0)) write(0,*) ' fnd_owner_loop remaining:',nreqst_max if (do_timings) call psb_toc(idx_loop_neigh) end do fnd_owner_loop @@ -269,16 +283,23 @@ subroutine psi_graph_fnd_owner(idx,iprc,idxmap,info) contains - subroutine psi_get_sample(ipntidx,idx,iprc,tidx,tsmpl,ns_in,ns_out) + subroutine psi_get_sample(ipntidx,idx,iprc,tidx,tsmpl,ns_in,ns_out,pad) implicit none integer(psb_ipk_), intent(inout) :: ipntidx integer(psb_lpk_), intent(in) :: idx(:) integer(psb_ipk_), intent(in) :: ns_in, iprc(:) integer(psb_lpk_), intent(out) :: tidx(:) integer(psb_ipk_), intent(out) :: tsmpl(:), ns_out + logical, intent(in), optional :: pad ! - integer(psb_ipk_) :: nv, ns + integer(psb_ipk_) :: nv, ns, k + logical :: pad_ + if (present(pad)) then + pad_ = pad + else + pad_ = .false. + end if nv = size(idx) ! ! Choose a sample, should it be done in this simplistic way? @@ -287,9 +308,11 @@ contains ! ! ns_in == 0 means that on the outside we figure there's ! nothing left, but we are here because we have to synchronize. - ! Make sure we sweep through the entire vector immediately + ! Make sure we sweep through the entire vector immediately. + ! But also make sure we do not overrun tsmpl ! if (ns == 0) ns = nv + ns = min(ns,size(tsmpl)) ns_out = 0 do while (ipntidx<= nv) @@ -301,6 +324,13 @@ contains ipntidx = ipntidx + 1 if (ns_out >= ns) exit end do + if (pad_) then + do k = ns_out+1, ns + tsmpl(k) = -1 + tidx(k) = -1 + end do + ns_out = ns + end if end subroutine psi_get_sample diff --git a/base/internals/psi_indx_map_fnd_owner.F90 b/base/internals/psi_indx_map_fnd_owner.F90 index 0aee08065..e11ad0b28 100644 --- a/base/internals/psi_indx_map_fnd_owner.F90 +++ b/base/internals/psi_indx_map_fnd_owner.F90 @@ -74,7 +74,8 @@ subroutine psi_indx_map_fnd_owner(idx,iprc,idxmap,info) integer(psb_ipk_), allocatable :: hhidx(:) integer(psb_mpk_) :: icomm, minfo, iictxt - integer(psb_ipk_) :: i, err_act, hsize, nv + integer(psb_ipk_) :: i, err_act, hsize + integer(psb_lpk_) :: nv integer(psb_lpk_) :: mglob integer(psb_ipk_) :: ictxt,np,me, nresp logical, parameter :: gettime=.false. @@ -140,7 +141,66 @@ subroutine psi_indx_map_fnd_owner(idx,iprc,idxmap,info) else - call psi_graph_fnd_owner(idx,iprc,idxmap,info) + if (allocated(idxmap%halo_owner)) then + ! + ! Maybe we are coming here after a REINIT event. + ! In this case, reuse the existing information as much as possible. + ! + block + integer(psb_ipk_), allocatable :: tprc(:), lidx(:) + integer(psb_lpk_), allocatable :: tidx(:) + integer(psb_lpk_) :: k1, k2, nh + allocate(lidx(nv),stat=info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Allocate') + goto 9999 + end if + ! + ! Get local answers, if any + ! + call idxmap%g2l(idx,lidx,info,owned=.false.) + call idxmap%fnd_halo_owner(lidx,iprc,info) + + nh = count(iprc<0) + !write(0,*) me,'Going through new impl from ',nv,' to ',nh + allocate(tidx(nh),tprc(nh),stat=info) + if (info /= psb_success_) then + call psb_errpush(psb_err_from_subroutine_,name,a_err='Allocate') + goto 9999 + end if + ! + ! Prepare remote queries + ! + k2 = 0 + do k1 = 1, nv + if (iprc(k1) < 0) then + k2 = k2 + 1 + if (k2 > nh) then + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='Wrong auxiliary count') + goto 9999 + end if + tidx(k2) = idx(k1) + end if + end do + call psi_graph_fnd_owner(tidx,tprc,idxmap,info) + k2 = 0 + do k1 = 1, nv + if (iprc(k1) < 0) then + k2 = k2 + 1 + if (k2 > nh) then + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='Wrong auxiliary count') + goto 9999 + end if + iprc(k1) = tprc(k2) + end if + end do + end block + else + call psi_graph_fnd_owner(idx,iprc,idxmap,info) + end if + end if diff --git a/base/modules/Makefile b/base/modules/Makefile index 21525a3c9..6c19b2479 100644 --- a/base/modules/Makefile +++ b/base/modules/Makefile @@ -153,9 +153,13 @@ penv/psi_collective_mod.o: penv/psi_e_collective_mod.o \ penv/psi_z_collective_mod.o penv/psi_m_p2p_mod.o penv/psi_e_p2p_mod.o penv/psi_s_p2p_mod.o \ -penv/psi_d_p2p_mod.o penv/psi_c_p2p_mod.o penv/psi_z_p2p_mod.o\ +penv/psi_d_p2p_mod.o penv/psi_c_p2p_mod.o penv/psi_z_p2p_mod.o: penv/psi_penv_mod.o + penv/psi_e_collective_mod.o penv/psi_m_collective_mod.o penv/psi_s_collective_mod.o \ -penv/psi_d_collective_mod.o penv/psi_c_collective_mod.o penv/psi_z_collective_mod.o: penv/psi_penv_mod.o +penv/psi_d_collective_mod.o penv/psi_c_collective_mod.o penv/psi_z_collective_mod.o: penv/psi_penv_mod.o \ + penv/psi_m_p2p_mod.o penv/psi_e_p2p_mod.o penv/psi_s_p2p_mod.o \ + penv/psi_d_p2p_mod.o penv/psi_c_p2p_mod.o penv/psi_z_p2p_mod.o + auxil/psb_string_mod.o desc/psb_desc_const_mod.o psi_comm_buffers_mod.o: psb_const_mod.o desc/psb_hash_mod.o: psb_realloc_mod.o psb_const_mod.o desc/psb_desc_const_mod.o diff --git a/base/modules/auxil/psb_i2_hsort_mod.f90 b/base/modules/auxil/psb_i2_hsort_mod.f90 new file mode 100644 index 000000000..0878f86e6 --- /dev/null +++ b/base/modules/auxil/psb_i2_hsort_mod.f90 @@ -0,0 +1,125 @@ +! +! 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. +! +! +! +! Sorting routines +! References: +! D. Knuth +! The Art of Computer Programming, vol. 3 +! Addison-Wesley +! +! Aho, Hopcroft, Ullman +! Data Structures and Algorithms +! Addison-Wesley +! +module psb_i2_hsort_mod + use psb_const_mod + + interface psb_hsort + subroutine psb_i2hsort(x,ix,dir,flag) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), optional, intent(in) :: dir, flag + integer(psb_ipk_), optional, intent(inout) :: ix(:) + end subroutine psb_i2hsort + end interface psb_hsort + + + interface psi_insert_heap + subroutine psi_i2_insert_heap(key,last,heap,dir,info) + import + implicit none + + ! + ! Input: + ! key: the new value + ! last: pointer to the last occupied element in heap + ! heap: the heap + ! dir: sorting direction + + integer(psb_i2pk_), intent(in) :: key + integer(psb_i2pk_), intent(inout) :: heap(:) + integer(psb_ipk_), intent(in) :: dir + integer(psb_ipk_), intent(inout) :: last + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2_insert_heap + end interface psi_insert_heap + + interface psi_idx_insert_heap + subroutine psi_i2_idx_insert_heap(key,index,last,heap,idxs,dir,info) + import + implicit none + + ! + ! Input: + ! key: the new value + ! last: pointer to the last occupied element in heap + ! heap: the heap + ! dir: sorting direction + + integer(psb_i2pk_), intent(in) :: key + integer(psb_i2pk_), intent(inout) :: heap(:) + integer(psb_ipk_), intent(in) :: index + integer(psb_ipk_), intent(in) :: dir + integer(psb_ipk_), intent(inout) :: idxs(:) + integer(psb_ipk_), intent(inout) :: last + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2_idx_insert_heap + end interface psi_idx_insert_heap + + + interface psi_heap_get_first + subroutine psi_i2_heap_get_first(key,last,heap,dir,info) + import + implicit none + integer(psb_i2pk_), intent(inout) :: key + integer(psb_ipk_), intent(inout) :: last + integer(psb_ipk_), intent(in) :: dir + integer(psb_i2pk_), intent(inout) :: heap(:) + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2_heap_get_first + end interface psi_heap_get_first + + interface psi_idx_heap_get_first + subroutine psi_i2_idx_heap_get_first(key,index,last,heap,idxs,dir,info) + import + integer(psb_i2pk_), intent(inout) :: key + integer(psb_ipk_), intent(out) :: index + integer(psb_i2pk_), intent(inout) :: heap(:) + integer(psb_ipk_), intent(in) :: dir + integer(psb_ipk_), intent(inout) :: last + integer(psb_ipk_), intent(inout) :: idxs(:) + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2_idx_heap_get_first + end interface psi_idx_heap_get_first + + +end module psb_i2_hsort_mod diff --git a/base/modules/auxil/psb_i2_ip_reord_mod.F90 b/base/modules/auxil/psb_i2_ip_reord_mod.F90 new file mode 100644 index 000000000..985b3cd42 --- /dev/null +++ b/base/modules/auxil/psb_i2_ip_reord_mod.F90 @@ -0,0 +1,320 @@ +! +! 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. +! +! +! +! Reorder (an) input vector(s) based on a list sort output. +! Based on: D. E. Knuth: The Art of Computer Programming +! vol. 3: Sorting and Searching, Addison Wesley, 1973 +! ex. 5.2.12 +! +! +module psb_i2_ip_reord_mod + use psb_const_mod + + interface psb_ip_reord + module procedure psb_ip_reord_i21m,& + & psb_ip_reord_i21m1, psb_ip_reord_i21m2,& + & psb_ip_reord_i21m3 + module procedure psb_ip_reord_i21e,& + & psb_ip_reord_i21e1, psb_ip_reord_i21e2,& + & psb_ip_reord_i21e3 + + + end interface + +contains + + subroutine psb_ip_reord_i21m(n,x,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_mpk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_mpk_) :: lswap, lp, k + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21m + + subroutine psb_ip_reord_i21m1(n,x,indx,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_mpk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_mpk_) :: indx(*) + integer(psb_mpk_) :: lswap, lp, k, ixswap + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + ixswap = indx(lp) + indx(lp) = indx(k) + indx(k) = ixswap + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21m1 + + subroutine psb_ip_reord_i21m2(n,x,i1,i2,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_mpk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_mpk_) :: i1(*), i2(*) + + + integer(psb_mpk_) :: lswap, lp, k, isw1, isw2 + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + isw1 = i1(lp) + i1(lp) = i1(k) + i1(k) = isw1 + isw2 = i2(lp) + i2(lp) = i2(k) + i2(k) = isw2 + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21m2 + + subroutine psb_ip_reord_i21m3(n,x,i1,i2,i3,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_mpk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_mpk_) :: i1(*), i2(*), i3(*) + + integer(psb_mpk_) :: lswap, lp, k, isw1, isw2, isw3 + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + isw1 = i1(lp) + i1(lp) = i1(k) + i1(k) = isw1 + isw2 = i2(lp) + i2(lp) = i2(k) + i2(k) = isw2 + isw3 = i3(lp) + i3(lp) = i3(k) + i3(k) = isw3 + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21m3 + + + subroutine psb_ip_reord_i21e(n,x,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_epk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_epk_) :: lswap, lp, k + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21e + + subroutine psb_ip_reord_i21e1(n,x,indx,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_epk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_epk_) :: indx(*) + integer(psb_epk_) :: lswap, lp, k, ixswap + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + ixswap = indx(lp) + indx(lp) = indx(k) + indx(k) = ixswap + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21e1 + + subroutine psb_ip_reord_i21e2(n,x,i1,i2,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_epk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_epk_) :: i1(*), i2(*) + + + integer(psb_epk_) :: lswap, lp, k, isw1, isw2 + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + isw1 = i1(lp) + i1(lp) = i1(k) + i1(k) = isw1 + isw2 = i2(lp) + i2(lp) = i2(k) + i2(k) = isw2 + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21e2 + + subroutine psb_ip_reord_i21e3(n,x,i1,i2,i3,iaux) + integer(psb_ipk_), intent(in) :: n + integer(psb_epk_) :: iaux(0:*) + integer(psb_i2pk_) :: x(*) + integer(psb_epk_) :: i1(*), i2(*), i3(*) + + integer(psb_epk_) :: lswap, lp, k, isw1, isw2, isw3 + integer(psb_i2pk_) :: swap + + lp = iaux(0) + k = 1 + do + if ((lp == 0).or.(k>n)) exit + do + if (lp >= k) exit + lp = iaux(lp) + end do + swap = x(lp) + x(lp) = x(k) + x(k) = swap + isw1 = i1(lp) + i1(lp) = i1(k) + i1(k) = isw1 + isw2 = i2(lp) + i2(lp) = i2(k) + i2(k) = isw2 + isw3 = i3(lp) + i3(lp) = i3(k) + i3(k) = isw3 + lswap = iaux(lp) + iaux(lp) = iaux(k) + iaux(k) = lp + lp = lswap + k = k + 1 + enddo + return + end subroutine psb_ip_reord_i21e3 + +end module psb_i2_ip_reord_mod diff --git a/base/modules/auxil/psb_i2_isort_mod.f90 b/base/modules/auxil/psb_i2_isort_mod.f90 new file mode 100644 index 000000000..115da75cb --- /dev/null +++ b/base/modules/auxil/psb_i2_isort_mod.f90 @@ -0,0 +1,105 @@ +! +! 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. +! +! +! +! Sorting routines +! References: +! D. Knuth +! The Art of Computer Programming, vol. 3 +! Addison-Wesley +! +! Aho, Hopcroft, Ullman +! Data Structures and Algorithms +! Addison-Wesley +! +module psb_i2_isort_mod + use psb_const_mod + + interface psb_isort + subroutine psb_i2isort(x,ix,dir,flag) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), optional, intent(in) :: dir, flag + integer(psb_ipk_), optional, intent(inout) :: ix(:) + end subroutine psb_i2isort + end interface psb_isort + + + + interface + subroutine psi_i2isrx_up(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2isrx_up + subroutine psi_i2isrx_dw(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2isrx_dw + subroutine psi_i2isr_up(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2isr_up + subroutine psi_i2isr_dw(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2isr_dw + subroutine psi_i2aisrx_up(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aisrx_up + subroutine psi_i2aisrx_dw(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aisrx_dw + subroutine psi_i2aisr_up(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aisr_up + subroutine psi_i2aisr_dw(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aisr_dw + end interface + + +end module psb_i2_isort_mod diff --git a/base/modules/auxil/psb_i2_msort_mod.f90 b/base/modules/auxil/psb_i2_msort_mod.f90 new file mode 100644 index 000000000..caad09713 --- /dev/null +++ b/base/modules/auxil/psb_i2_msort_mod.f90 @@ -0,0 +1,111 @@ +! +! 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. +! +! +! +! Sorting routines +! References: +! D. Knuth +! The Art of Computer Programming, vol. 3 +! Addison-Wesley +! +! Aho, Hopcroft, Ullman +! Data Structures and Algorithms +! Addison-Wesley +! +module psb_i2_msort_mod + use psb_const_mod + + interface psb_isaperm + logical function psb_i2isaperm(n,eip) + import + integer(psb_i2pk_), intent(in) :: n + integer(psb_i2pk_), intent(in) :: eip(n) + end function psb_i2isaperm + end interface psb_isaperm + + interface psb_msort_unique + subroutine psb_i2msort_u(x,nout,dir) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(out) :: nout + integer(psb_ipk_), optional, intent(in) :: dir + end subroutine psb_i2msort_u + end interface psb_msort_unique + + + interface psb_msort + subroutine psb_i2msort(x,ix,dir,flag) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), optional, intent(in) :: dir, flag + integer(psb_ipk_), optional, intent(inout) :: ix(:) + end subroutine psb_i2msort + end interface psb_msort + + + interface psi_msort_up + subroutine psi_i2_msort_up(n,k,l,iret) + import + implicit none + integer(psb_ipk_) :: n, iret + integer(psb_i2pk_) :: k(n) + integer(psb_ipk_) :: l(0:n+1) + end subroutine psi_i2_msort_up + end interface psi_msort_up + interface psi_msort_dw + subroutine psi_i2_msort_dw(n,k,l,iret) + import + implicit none + integer(psb_ipk_) :: n, iret + integer(psb_i2pk_) :: k(n) + integer(psb_ipk_) :: l(0:n+1) + end subroutine psi_i2_msort_dw + end interface psi_msort_dw + interface psi_amsort_up + subroutine psi_i2_amsort_up(n,k,l,iret) + import + implicit none + integer(psb_ipk_) :: n, iret + integer(psb_i2pk_) :: k(n) + integer(psb_ipk_) :: l(0:n+1) + end subroutine psi_i2_amsort_up + end interface psi_amsort_up + interface psi_amsort_dw + subroutine psi_i2_amsort_dw(n,k,l,iret) + import + implicit none + integer(psb_ipk_) :: n, iret + integer(psb_i2pk_) :: k(n) + integer(psb_ipk_) :: l(0:n+1) + end subroutine psi_i2_amsort_dw + end interface psi_amsort_dw + +end module psb_i2_msort_mod diff --git a/base/modules/auxil/psb_i2_qsort_mod.f90 b/base/modules/auxil/psb_i2_qsort_mod.f90 new file mode 100644 index 000000000..944a436ec --- /dev/null +++ b/base/modules/auxil/psb_i2_qsort_mod.f90 @@ -0,0 +1,123 @@ +! +! 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. +! +! +! +! Sorting routines +! References: +! D. Knuth +! The Art of Computer Programming, vol. 3 +! Addison-Wesley +! +! Aho, Hopcroft, Ullman +! Data Structures and Algorithms +! Addison-Wesley +! +module psb_i2_qsort_mod + use psb_const_mod + + + + interface psb_bsrch + function psb_i2bsrch(key,n,v) result(ipos) + import + integer(psb_ipk_) :: ipos, n + integer(psb_i2pk_) :: key + integer(psb_i2pk_) :: v(:) + end function psb_i2bsrch + end interface psb_bsrch + + interface psb_ssrch + function psb_i2ssrch(key,n,v) result(ipos) + import + implicit none + integer(psb_ipk_) :: ipos, n + integer(psb_i2pk_) :: key + integer(psb_i2pk_) :: v(:) + end function psb_i2ssrch + end interface psb_ssrch + + interface psb_qsort + subroutine psb_i2qsort(x,ix,dir,flag) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), optional, intent(in) :: dir, flag + integer(psb_ipk_), optional, intent(inout) :: ix(:) + end subroutine psb_i2qsort + end interface psb_qsort + + interface + subroutine psi_i2qsrx_up(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2qsrx_up + subroutine psi_i2qsrx_dw(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2qsrx_dw + subroutine psi_i2qsr_up(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2qsr_up + subroutine psi_i2qsr_dw(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2qsr_dw + subroutine psi_i2aqsrx_up(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aqsrx_up + subroutine psi_i2aqsrx_dw(n,x,ix) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(inout) :: ix(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aqsrx_dw + subroutine psi_i2aqsr_up(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aqsr_up + subroutine psi_i2aqsr_dw(n,x) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: n + end subroutine psi_i2aqsr_dw + end interface + +end module psb_i2_qsort_mod diff --git a/base/modules/auxil/psb_i2_realloc_mod.F90 b/base/modules/auxil/psb_i2_realloc_mod.F90 new file mode 100644 index 000000000..4bc4da320 --- /dev/null +++ b/base/modules/auxil/psb_i2_realloc_mod.F90 @@ -0,0 +1,1027 @@ +! +! 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. +! +! +module psb_i2_realloc_mod + use psb_const_mod + + implicit none + + ! + ! psb_realloc will reallocate the input array to have exactly + ! the size specified, possibly shortening it. + ! + Interface psb_realloc + module procedure psb_r_m_i2_rk1 + module procedure psb_r_m_i2_rk2 + module procedure psb_r_e_i2_rk1 + module procedure psb_r_e_i2_rk2 + module procedure psb_r_me_i2_rk2 + module procedure psb_r_em_i2_rk2 + + module procedure psb_r_m_2_i2_rk1 + module procedure psb_r_e_2_i2_rk1 + + end Interface psb_realloc + + interface psb_move_alloc + module procedure psb_move_alloc_i2_rk1, psb_move_alloc_i2_rk2 + end interface psb_move_alloc + + Interface psb_safe_ab_cpy + module procedure psb_ab_cpy_i2_rk1, psb_ab_cpy_i2_rk2 + end Interface psb_safe_ab_cpy + + Interface psb_safe_cpy + module procedure psb_cpy_i2_rk1, psb_cpy_i2_rk2 + end Interface psb_safe_cpy + + ! + ! psb_ensure_size will reallocate the input array if necessary + ! to guarantee that its size is at least as large as the + ! value required, usually with some room to spare. + ! + interface psb_ensure_size + module procedure psb_ensure_m_sz_i2_rk1, psb_ensure_e_sz_i2_rk1 + end Interface psb_ensure_size + + ! + ! psb_size returns 0 if argument is not allocated. + ! + interface psb_size + module procedure psb_size_i2_rk1, psb_size_i2_rk2 + end interface psb_size + + +Contains + + Subroutine psb_r_m_i2_rk1(len,rrax,info,pad,lb) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_mpk_),Intent(in) :: len + integer(psb_i2pk_), allocatable, intent(inout) :: rrax(:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_mpk_), optional, intent(in) :: lb + + ! ...Local Variables + integer(psb_i2pk_),allocatable :: tmp(:) + integer(psb_mpk_) :: dim, lb_, lbi,ub_ + integer(psb_ipk_) :: err_act,err + character(len=20) :: name + logical, parameter :: debug=.false. + + name='psb_r_m_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + if (debug) write(psb_err_unit,*) 'reallocate D',len + + if (present(lb)) then + lb_ = lb + else + lb_ = 1 + endif + if ((len<0)) then + err=4025 + call psb_errpush(err,name, l_err=(/len*1_psb_lpk_/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + ub_ = lb_ + len-1 + + if (allocated(rrax)) then + dim = size(rrax) + lbi = lbound(rrax,1) + If ((dim /= len).or.(lbi /= lb_)) Then + Allocate(tmp(lb_:ub_),stat=info) + if (info /= psb_success_) then + err=4025 + call psb_errpush(err,name, l_err=(/len*1_psb_lpk_/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb_:lb_-1+min(len,dim))=rrax(lbi:lbi-1+min(len,dim)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + Allocate(rrax(lb_:ub_),stat=info) + if (info /= psb_success_) then + err=4025 + call psb_errpush(err,name, l_err=(/len*1_psb_lpk_/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb_-1+dim+1:lb_-1+len) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_m_i2_rk1 + + Subroutine psb_r_m_i2_rk2(len1,len2,rrax,info,pad,lb1,lb2) + use psb_error_mod + ! ...Subroutine Arguments + integer(psb_mpk_),Intent(in) :: len1,len2 + integer(psb_i2pk_),allocatable :: rrax(:,:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_mpk_),Intent(in), optional :: lb1,lb2 + + ! ...Local Variables + + integer(psb_i2pk_),allocatable :: tmp(:,:) + integer(psb_ipk_) :: err_act,err + integer(psb_mpk_) :: dim,dim2,lb1_, lb2_, ub1_, ub2_,lbi1, lbi2 + character(len=20) :: name + + name='psb_r_m_i2_rk2' + call psb_erractionsave(err_act) + info=psb_success_ + if (present(lb1)) then + lb1_ = lb1 + else + lb1_ = 1 + endif + if (present(lb2)) then + lb2_ = lb2 + else + lb2_ = 1 + endif + ub1_ = lb1_ + len1 -1 + ub2_ = lb2_ + len2 -1 + + if (len1 < 0) then + err=4025 + call psb_errpush(err,name, l_err=(/len1*1_psb_lpk_/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + if (len2 < 0) then + err=4025 + call psb_errpush(err,name, l_err=(/len2*1_psb_lpk_/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + + + if (allocated(rrax)) then + dim = size(rrax,1) + lbi1 = lbound(rrax,1) + dim2 = size(rrax,2) + lbi2 = lbound(rrax,2) + If ((dim /= len1).or.(dim2 /= len2).or.(lbi1 /= lb1_)& + & .or.(lbi2 /= lb2_)) Then + Allocate(tmp(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + call psb_errpush(err,name, l_err=(/len1*1_psb_lpk_*len2/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb1_:lb1_-1+min(len1,dim),lb2_:lb2_-1+min(len2,dim2)) = & + & rrax(lbi1:lbi1-1+min(len1,dim),lbi2:lbi2-1+min(len2,dim2)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + dim2 = 0 + Allocate(rrax(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + call psb_errpush(err,name, l_err=(/len1*1_psb_lpk_*len2/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb1_-1+dim+1:lb1_-1+len1,:) = pad + rrax(lb1_:lb1_-1+dim,lb2_-1+dim2+1:lb2_-1+len2) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_m_i2_rk2 + + + Subroutine psb_r_e_i2_rk1(len,rrax,info,pad,lb) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_epk_),Intent(in) :: len + integer(psb_i2pk_), allocatable, intent(inout) :: rrax(:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_epk_), optional, intent(in) :: lb + + ! ...Local Variables + integer(psb_i2pk_),allocatable :: tmp(:) + integer(psb_epk_) :: dim, lb_, lbi,ub_ + integer(psb_ipk_) :: iplen + integer(psb_ipk_) :: err_act,err + character(len=20) :: name + logical, parameter :: debug=.false. + + name='psb_r_m_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + if (debug) write(psb_err_unit,*) 'reallocate D',len + + if (present(lb)) then + lb_ = lb + else + lb_ = 1 + endif + if ((len<0)) then + err=4025 + iplen = len + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + ub_ = lb_ + len-1 + + if (allocated(rrax)) then + dim = size(rrax) + lbi = lbound(rrax,1) + If ((dim /= len).or.(lbi /= lb_)) Then + Allocate(tmp(lb_:ub_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb_:lb_-1+min(len,dim))=rrax(lbi:lbi-1+min(len,dim)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + Allocate(rrax(lb_:ub_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb_-1+dim+1:lb_-1+len) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_e_i2_rk1 + + Subroutine psb_r_e_i2_rk2(len1,len2,rrax,info,pad,lb1,lb2) + use psb_error_mod + ! ...Subroutine Arguments + integer(psb_epk_),Intent(in) :: len1,len2 + integer(psb_i2pk_),allocatable :: rrax(:,:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_epk_),Intent(in), optional :: lb1,lb2 + + ! ...Local Variables + + integer(psb_i2pk_),allocatable :: tmp(:,:) + integer(psb_ipk_) :: err_act,err, iplen + integer(psb_epk_) :: dim,dim2,lb1_, lb2_, ub1_, ub2_,lbi1, lbi2 + character(len=20) :: name + + name='psb_r_e_i2_rk2' + call psb_erractionsave(err_act) + info=psb_success_ + if (present(lb1)) then + lb1_ = lb1 + else + lb1_ = 1 + endif + if (present(lb2)) then + lb2_ = lb2 + else + lb2_ = 1 + endif + ub1_ = lb1_ + len1 -1 + ub2_ = lb2_ + len2 -1 + + if (len1 < 0) then + err=4025 + iplen = len1 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + if (len2 < 0) then + err=4025 + iplen = len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + + + if (allocated(rrax)) then + dim = size(rrax,1) + lbi1 = lbound(rrax,1) + dim2 = size(rrax,2) + lbi2 = lbound(rrax,2) + If ((dim /= len1).or.(dim2 /= len2).or.(lbi1 /= lb1_)& + & .or.(lbi2 /= lb2_)) Then + Allocate(tmp(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb1_:lb1_-1+min(len1,dim),lb2_:lb2_-1+min(len2,dim2)) = & + & rrax(lbi1:lbi1-1+min(len1,dim),lbi2:lbi2-1+min(len2,dim2)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + dim2 = 0 + Allocate(rrax(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb1_-1+dim+1:lb1_-1+len1,:) = pad + rrax(lb1_:lb1_-1+dim,lb2_-1+dim2+1:lb2_-1+len2) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_e_i2_rk2 + + Subroutine psb_r_me_i2_rk2(len1,len2,rrax,info,pad,lb1,lb2) + use psb_error_mod + ! ...Subroutine Arguments + integer(psb_mpk_),Intent(in) :: len1 + integer(psb_epk_),Intent(in) :: len2 + integer(psb_i2pk_),allocatable :: rrax(:,:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_mpk_),Intent(in), optional :: lb1,lb2 + + ! ...Local Variables + + integer(psb_i2pk_),allocatable :: tmp(:,:) + integer(psb_ipk_) :: err_act,err, iplen + integer(psb_mpk_) :: dim,lb1_, lb2_, ub1_, ub2_,lbi1, lbi2 + integer(psb_epk_) :: dim2 + character(len=20) :: name + + name='psb_r_me_i2_rk2' + call psb_erractionsave(err_act) + info=psb_success_ + if (present(lb1)) then + lb1_ = lb1 + else + lb1_ = 1 + endif + if (present(lb2)) then + lb2_ = lb2 + else + lb2_ = 1 + endif + ub1_ = lb1_ + len1 -1 + ub2_ = lb2_ + len2 -1 + + if (len1 < 0) then + err=4025 + iplen = len1 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + if (len2 < 0) then + err=4025 + iplen = len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + + + if (allocated(rrax)) then + dim = size(rrax,1) + lbi1 = lbound(rrax,1) + dim2 = size(rrax,2) + lbi2 = lbound(rrax,2) + If ((dim /= len1).or.(dim2 /= len2).or.(lbi1 /= lb1_)& + & .or.(lbi2 /= lb2_)) Then + Allocate(tmp(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb1_:lb1_-1+min(len1,dim),lb2_:lb2_-1+min(len2,dim2)) = & + & rrax(lbi1:lbi1-1+min(len1,dim),lbi2:lbi2-1+min(len2,dim2)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + dim2 = 0 + Allocate(rrax(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name,i_err=(/iplen/),& + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb1_-1+dim+1:lb1_-1+len1,:) = pad + rrax(lb1_:lb1_-1+dim,lb2_-1+dim2+1:lb2_-1+len2) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_me_i2_rk2 + + Subroutine psb_r_em_i2_rk2(len1,len2,rrax,info,pad,lb1,lb2) + use psb_error_mod + ! ...Subroutine Arguments + integer(psb_epk_),Intent(in) :: len1 + integer(psb_mpk_),Intent(in) :: len2 + integer(psb_i2pk_),allocatable :: rrax(:,:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + integer(psb_mpk_),Intent(in), optional :: lb1,lb2 + + ! ...Local Variables + + integer(psb_i2pk_),allocatable :: tmp(:,:) + integer(psb_ipk_) :: err_act,err, iplen + integer(psb_mpk_) :: dim2,lb1_, lb2_, ub1_, ub2_,lbi1, lbi2 + integer(psb_epk_) :: dim + character(len=20) :: name + + name='psb_r_me_i2_rk2' + call psb_erractionsave(err_act) + info=psb_success_ + if (present(lb1)) then + lb1_ = lb1 + else + lb1_ = 1 + endif + if (present(lb2)) then + lb2_ = lb2 + else + lb2_ = 1 + endif + ub1_ = lb1_ + len1 -1 + ub2_ = lb2_ + len2 -1 + + if (len1 < 0) then + err=4025 + iplen = len1 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + if (len2 < 0) then + err=4025 + iplen = len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + + + if (allocated(rrax)) then + dim = size(rrax,1) + lbi1 = lbound(rrax,1) + dim2 = size(rrax,2) + lbi2 = lbound(rrax,2) + If ((dim /= len1).or.(dim2 /= len2).or.(lbi1 /= lb1_)& + & .or.(lbi2 /= lb2_)) Then + Allocate(tmp(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + tmp(lb1_:lb1_-1+min(len1,dim),lb2_:lb2_-1+min(len2,dim2)) = & + & rrax(lbi1:lbi1-1+min(len1,dim),lbi2:lbi2-1+min(len2,dim2)) + call psb_move_alloc(tmp,rrax,info) + End If + else + dim = 0 + dim2 = 0 + Allocate(rrax(lb1_:ub1_,lb2_:ub2_),stat=info) + if (info /= psb_success_) then + err=4025 + iplen = len1*len2 + call psb_errpush(err,name, i_err=(/iplen/), & + & a_err='integer(psb_i2pk_)') + goto 9999 + end if + endif + if (present(pad)) then + rrax(lb1_-1+dim+1:lb1_-1+len1,:) = pad + rrax(lb1_:lb1_-1+dim,lb2_-1+dim2+1:lb2_-1+len2) = pad + endif + call psb_erractionrestore(err_act) + return + +9999 continue + info = err + call psb_error_handler(err_act) + return + + End Subroutine psb_r_em_i2_rk2 + + Subroutine psb_r_m_2_i2_rk1(len,rrax,y,info,pad) + use psb_error_mod + ! ...Subroutine Arguments + + integer(psb_mpk_),Intent(in) :: len + integer(psb_i2pk_),allocatable, intent(inout) :: rrax(:),y(:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + character(len=20) :: name + integer(psb_ipk_) :: err_act, err + + name='psb_r_m_2_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + call psb_realloc(len,rrax,info,pad=pad) + if (info /= psb_success_) then + err=4000 + call psb_errpush(err,name) + goto 9999 + end if + call psb_realloc(len,y,info,pad=pad) + if (info /= psb_success_) then + err=4000 + call psb_errpush(err,name) + goto 9999 + end if + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + End Subroutine psb_r_m_2_i2_rk1 + + Subroutine psb_r_e_2_i2_rk1(len,rrax,y,info,pad) + use psb_error_mod + ! ...Subroutine Arguments + + integer(psb_epk_),Intent(in) :: len + integer(psb_i2pk_),allocatable, intent(inout) :: rrax(:),y(:) + integer(psb_ipk_) :: info + integer(psb_i2pk_), optional, intent(in) :: pad + character(len=20) :: name + integer(psb_ipk_) :: err_act, err + + name='psb_r_m_2_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + call psb_realloc(len,rrax,info,pad=pad) + if (info /= psb_success_) then + err=4000 + call psb_errpush(err,name) + goto 9999 + end if + call psb_realloc(len,y,info,pad=pad) + if (info /= psb_success_) then + err=4000 + call psb_errpush(err,name) + goto 9999 + end if + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + End Subroutine psb_r_e_2_i2_rk1 + + + + subroutine psb_ab_cpy_i2_rk1(vin,vout,info) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_i2pk_), allocatable, intent(in) :: vin(:) + integer(psb_i2pk_), allocatable, intent(out) :: vout(:) + integer(psb_ipk_) :: info + ! ...Local Variables + + integer(psb_ipk_) :: isz,err_act,lb + character(len=20) :: name, char_err + logical, parameter :: debug=.false. + + name='psb_ab_cpy_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + if (allocated(vin)) then + isz = size(vin) + lb = lbound(vin,1) + call psb_realloc(isz,vout,info,lb=lb) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + char_err='psb_realloc' + call psb_errpush(info,name,a_err=char_err) + goto 9999 + else + vout(:) = vin(:) + endif + endif + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + end subroutine psb_ab_cpy_i2_rk1 + + subroutine psb_ab_cpy_i2_rk2(vin,vout,info) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_i2pk_), allocatable, intent(in) :: vin(:,:) + integer(psb_i2pk_), allocatable, intent(out) :: vout(:,:) + integer(psb_ipk_) :: info + ! ...Local Variables + + integer(psb_ipk_) :: isz1, isz2,err_act, lb1, lb2 + character(len=20) :: name, char_err + logical, parameter :: debug=.false. + + name='psb_ab_cpy_i2_rk2' + call psb_erractionsave(err_act) + info=psb_success_ + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + if (allocated(vin)) then + isz1 = size(vin,1) + isz2 = size(vin,2) + lb1 = lbound(vin,1) + lb2 = lbound(vin,2) + call psb_realloc(isz1,isz2,vout,info,lb1=lb1,lb2=lb2) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + char_err='psb_realloc' + call psb_errpush(info,name,a_err=char_err) + goto 9999 + else + vout(:,:) = vin(:,:) + endif + endif + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + end subroutine psb_ab_cpy_i2_rk2 + + + subroutine psb_cpy_i2_rk1(vin,vout,info) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_i2pk_), intent(in) :: vin(:) + integer(psb_i2pk_), allocatable, intent(out) :: vout(:) + integer(psb_ipk_) :: info + ! ...Local Variables + + integer(psb_ipk_) :: isz,err_act,lb + character(len=20) :: name, char_err + logical, parameter :: debug=.false. + + name='psb_cpy_i2_rk1' + call psb_erractionsave(err_act) + info=psb_success_ + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + isz = size(vin) + lb = lbound(vin,1) + call psb_realloc(isz,vout,info,lb=lb) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + char_err='psb_realloc' + call psb_errpush(info,name,a_err=char_err) + goto 9999 + else + vout(:) = vin(:) + endif + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + end subroutine psb_cpy_i2_rk1 + + subroutine psb_cpy_i2_rk2(vin,vout,info) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_i2pk_), intent(in) :: vin(:,:) + integer(psb_i2pk_), allocatable, intent(out) :: vout(:,:) + integer(psb_ipk_) :: info + ! ...Local Variables + + integer(psb_ipk_) :: isz1, isz2,err_act, lb1, lb2 + character(len=20) :: name, char_err + logical, parameter :: debug=.false. + + name='psb_safe_cpy' + call psb_erractionsave(err_act) + info=psb_success_ + if(psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + isz1 = size(vin,1) + isz2 = size(vin,2) + lb1 = lbound(vin,1) + lb2 = lbound(vin,2) + call psb_realloc(isz1,isz2,vout,info,lb1=lb1,lb2=lb2) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + char_err='psb_realloc' + call psb_errpush(info,name,a_err=char_err) + goto 9999 + else + vout(:,:) = vin(:,:) + endif + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + end subroutine psb_cpy_i2_rk2 + + + function psb_size_i2_rk1(vin) result(val) + integer(psb_epk_) :: val + integer(psb_i2pk_), allocatable, intent(in) :: vin(:) + + if (.not.allocated(vin)) then + val = 0 + else + val = size(vin) + end if + end function psb_size_i2_rk1 + + + function psb_size_i2_rk2(vin,dim) result(val) + integer(psb_epk_) :: val + integer(psb_i2pk_), allocatable, intent(in) :: vin(:,:) + integer(psb_ipk_), optional :: dim + integer(psb_ipk_) :: dim_ + + + if (.not.allocated(vin)) then + val = 0 + else + if (present(dim)) then + dim_= dim + val = size(vin,dim=dim_) + else + val = size(vin) + end if + end if + end function psb_size_i2_rk2 + + Subroutine psb_ensure_m_sz_i2_rk1(len,v,info,pad,addsz,newsz) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_mpk_),Intent(in) :: len + integer(psb_i2pk_),allocatable, intent(inout) :: v(:) + integer(psb_ipk_) :: info + integer(psb_mpk_), optional, intent(in) :: addsz,newsz + integer(psb_i2pk_), optional, intent(in) :: pad + ! ...Local Variables + character(len=20) :: name + logical, parameter :: debug=.false. + integer(psb_ipk_) :: err_act + integer(psb_mpk_) :: isz + + name='psb_ensure_m_sz_i2_rk1' + call psb_erractionsave(err_act) + info = psb_success_ + + if (psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + If (len > psb_size(v)) Then + if (present(newsz)) then + isz = (max(len+1,newsz)) + else + if (present(addsz)) then + isz = len+max(1,addsz) + else + isz = max(len+10, int(1.25*len)) + endif + endif + + call psb_realloc(isz,v,info,pad=pad) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_realloc') + goto 9999 + End If + end If + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + + End Subroutine psb_ensure_m_sz_i2_rk1 + + Subroutine psb_ensure_e_sz_i2_rk1(len,v,info,pad,addsz,newsz) + use psb_error_mod + + ! ...Subroutine Arguments + integer(psb_epk_),Intent(in) :: len + integer(psb_i2pk_),allocatable, intent(inout) :: v(:) + integer(psb_ipk_) :: info + integer(psb_epk_), optional, intent(in) :: addsz,newsz + integer(psb_i2pk_), optional, intent(in) :: pad + ! ...Local Variables + character(len=20) :: name + logical, parameter :: debug=.false. + integer(psb_ipk_) :: err_act + integer(psb_epk_) :: isz + + name='psb_ensure_m_sz_i2_rk1' + call psb_erractionsave(err_act) + info = psb_success_ + + if (psb_errstatus_fatal()) then + info=psb_err_from_subroutine_ + goto 9999 + end if + + If (len > psb_size(v)) Then + if (present(newsz)) then + isz = (max(len+1,newsz)) + else + if (present(addsz)) then + isz = len+max(1,addsz) + else + isz = max(len+10, int(1.25*len)) + endif + endif + + call psb_realloc(isz,v,info,pad=pad) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_realloc') + goto 9999 + End If + end If + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + + + End Subroutine psb_ensure_e_sz_i2_rk1 + + Subroutine psb_move_alloc_i2_rk1(vin,vout,info) + use psb_error_mod + integer(psb_i2pk_), allocatable, intent(inout) :: vin(:),vout(:) + integer(psb_ipk_), intent(out) :: info + ! + ! + info=psb_success_ + call move_alloc(vin,vout) + + end Subroutine psb_move_alloc_i2_rk1 + + Subroutine psb_move_alloc_i2_rk2(vin,vout,info) + use psb_error_mod + integer(psb_i2pk_), allocatable, intent(inout) :: vin(:,:),vout(:,:) + integer(psb_ipk_), intent(out) :: info + ! + ! + info=psb_success_ + + call move_alloc(vin,vout) + + end Subroutine psb_move_alloc_i2_rk2 + +end module psb_i2_realloc_mod diff --git a/base/modules/auxil/psi_i2_serial_mod.f90 b/base/modules/auxil/psi_i2_serial_mod.f90 new file mode 100644 index 000000000..bc0df7c55 --- /dev/null +++ b/base/modules/auxil/psi_i2_serial_mod.f90 @@ -0,0 +1,143 @@ +! +! 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. +! +! +module psi_i2_serial_mod + use psb_const_mod, only : psb_ipk_, psb_lpk_, psb_mpk_, psb_epk_ + + interface psb_gelp + ! 2-D version + subroutine psb_i2gelp(trans,iperm,x,info) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_i2pk_), intent(inout) :: x(:,:) + integer(psb_ipk_), intent(in) :: iperm(:) + integer(psb_ipk_), intent(out) :: info + character, intent(in) :: trans + end subroutine psb_i2gelp + subroutine psb_i2gelpv(trans,iperm,x,info) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_ipk_), intent(in) :: iperm(:) + integer(psb_ipk_), intent(out) :: info + character, intent(in) :: trans + end subroutine psb_i2gelpv + end interface psb_gelp + + interface psb_geaxpby + subroutine psi_i2axpby(m,n,alpha, x, beta, y, info) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_), intent(in) :: m, n + integer(psb_i2pk_), intent (in) :: x(:,:) + integer(psb_i2pk_), intent (inout) :: y(:,:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2axpby + subroutine psi_i2axpbyv(m,alpha, x, beta, y, info) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_), intent(in) :: m + integer(psb_i2pk_), intent (in) :: x(:) + integer(psb_i2pk_), intent (inout) :: y(:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2axpbyv + subroutine psi_i2axpbyv2(m,alpha, x, beta, y, z, info) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_), intent(in) :: m + integer(psb_i2pk_), intent (in) :: x(:) + integer(psb_i2pk_), intent (in) :: y(:) + integer(psb_i2pk_), intent (in) :: z(:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2axpbyv2 + end interface psb_geaxpby + + interface psi_gth + subroutine psi_i2gthmv(n,k,idx,alpha,x,beta,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:),alpha,beta + end subroutine psi_i2gthmv + subroutine psi_i2gthv(n,idx,alpha,x,beta,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: x(:), y(:),alpha,beta + end subroutine psi_i2gthv + subroutine psi_i2gthzmv(n,k,idx,x,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:) + + end subroutine psi_i2gthzmv + subroutine psi_i2gthzmm(n,k,idx,x,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:,:) + + end subroutine psi_i2gthzmm + subroutine psi_i2gthzv(n,idx,x,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: x(:), y(:) + end subroutine psi_i2gthzv + end interface psi_gth + + interface psi_sct + subroutine psi_i2sctmm(n,k,idx,x,beta,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: beta, x(:,:), y(:,:) + end subroutine psi_i2sctmm + subroutine psi_i2sctmv(n,k,idx,x,beta,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: beta, x(:), y(:,:) + end subroutine psi_i2sctmv + subroutine psi_i2sctv(n,idx,x,beta,y) + import :: psb_ipk_, psb_lpk_,psb_mpk_, psb_epk_ + implicit none + + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: beta, x(:), y(:) + end subroutine psi_i2sctv + end interface psi_sct + +end module psi_i2_serial_mod diff --git a/base/modules/comm/psb_e_comm_a_mod.f90 b/base/modules/comm/psb_e_comm_a_mod.f90 index 19f1cb012..46057d94c 100644 --- a/base/modules/comm/psb_e_comm_a_mod.f90 +++ b/base/modules/comm/psb_e_comm_a_mod.f90 @@ -30,7 +30,8 @@ ! ! module psb_e_comm_a_mod - use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_lpk_, psb_epk_, psb_mpk_ + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_lpk_, & + & psb_epk_, psb_mpk_, psb_i2pk_ interface psb_ovrl subroutine psb_eovrlm(x,desc_a,info,jx,ik,work,update,mode) diff --git a/base/modules/comm/psb_i2_comm_a_mod.f90 b/base/modules/comm/psb_i2_comm_a_mod.f90 new file mode 100644 index 000000000..09398722d --- /dev/null +++ b/base/modules/comm/psb_i2_comm_a_mod.f90 @@ -0,0 +1,123 @@ +! +! 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. +! +! +module psb_i2_comm_a_mod + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_lpk_, & + & psb_epk_, psb_mpk_, psb_i2pk_ + + interface psb_ovrl + subroutine psb_i2ovrlm(x,desc_a,info,jx,ik,work,update,mode) + import + implicit none + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), intent(inout), optional, target :: work(:) + integer(psb_ipk_), intent(in), optional :: update,jx,ik,mode + end subroutine psb_i2ovrlm + subroutine psb_i2ovrlv(x,desc_a,info,work,update,mode) + import + implicit none + integer(psb_i2pk_), intent(inout), target :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), intent(inout), optional, target :: work(:) + integer(psb_ipk_), intent(in), optional :: update,mode + end subroutine psb_i2ovrlv + end interface psb_ovrl + + interface psb_halo + subroutine psb_i2halom(x,desc_a,info,jx,ik,work,tran,mode,data) + import + implicit none + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), target, optional, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: mode,jx,ik,data + character, intent(in), optional :: tran + end subroutine psb_i2halom + subroutine psb_i2halov(x,desc_a,info,work,tran,mode,data) + import + implicit none + integer(psb_i2pk_), intent(inout) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_), target, optional, intent(inout) :: work(:) + integer(psb_ipk_), intent(in), optional :: mode,data + character, intent(in), optional :: tran + end subroutine psb_i2halov + end interface psb_halo + + + interface psb_scatter + subroutine psb_i2scatterm(globx, locx, desc_a, info, root) + import + implicit none + integer(psb_i2pk_), intent(out), allocatable :: locx(:,:) + integer(psb_i2pk_), intent(in) :: globx(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + end subroutine psb_i2scatterm + subroutine psb_i2scatterv(globx, locx, desc_a, info, root) + import + implicit none + integer(psb_i2pk_), intent(out), allocatable :: locx(:) + integer(psb_i2pk_), intent(in) :: globx(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + end subroutine psb_i2scatterv + end interface psb_scatter + + interface psb_gather + subroutine psb_i2gatherm(globx, locx, desc_a, info, root) + import + implicit none + integer(psb_i2pk_), intent(in) :: locx(:,:) + integer(psb_i2pk_), intent(out), allocatable :: globx(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + end subroutine psb_i2gatherm + subroutine psb_i2gatherv(globx, locx, desc_a, info, root) + import + implicit none + integer(psb_i2pk_), intent(in) :: locx(:) + integer(psb_i2pk_), intent(out), allocatable :: globx(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: root + end subroutine psb_i2gatherv + end interface psb_gather + +end module psb_i2_comm_a_mod diff --git a/base/modules/comm/psb_m_comm_a_mod.f90 b/base/modules/comm/psb_m_comm_a_mod.f90 index 91124a534..dbec118a8 100644 --- a/base/modules/comm/psb_m_comm_a_mod.f90 +++ b/base/modules/comm/psb_m_comm_a_mod.f90 @@ -30,7 +30,8 @@ ! ! module psb_m_comm_a_mod - use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_lpk_, psb_epk_, psb_mpk_ + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_lpk_, & + & psb_epk_, psb_mpk_, psb_i2pk_ interface psb_ovrl subroutine psb_movrlm(x,desc_a,info,jx,ik,work,update,mode) diff --git a/base/modules/comm/psi_i2_comm_a_mod.f90 b/base/modules/comm/psi_i2_comm_a_mod.f90 new file mode 100644 index 000000000..f67b56541 --- /dev/null +++ b/base/modules/comm/psi_i2_comm_a_mod.f90 @@ -0,0 +1,166 @@ +! +! 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. +! +! +module psi_i2_comm_a_mod + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, psb_epk_ + + interface psi_swapdata + subroutine psi_i2swapdatam(flag,n,beta,y,desc_a,work,info,data) + import + integer(psb_ipk_), intent(in) :: flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_),target :: work(:) + type(psb_desc_type), target :: desc_a + integer(psb_ipk_), optional :: data + end subroutine psi_i2swapdatam + subroutine psi_i2swapdatav(flag,beta,y,desc_a,work,info,data) + import + integer(psb_ipk_), intent(in) :: flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_),target :: work(:) + type(psb_desc_type), target :: desc_a + integer(psb_ipk_), optional :: data + end subroutine psi_i2swapdatav + subroutine psi_i2swapidxm(ictxt,icomm,flag,n,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + import + integer(psb_ipk_), intent(in) :: ictxt,icomm,flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_),target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd,totrcv + end subroutine psi_i2swapidxm + subroutine psi_i2swapidxv(ictxt,icomm,flag,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + import + integer(psb_ipk_), intent(in) :: ictxt,icomm,flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_),target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd,totrcv + end subroutine psi_i2swapidxv + end interface psi_swapdata + + + interface psi_swaptran + subroutine psi_i2swaptranm(flag,n,beta,y,desc_a,work,info,data) + import + integer(psb_ipk_), intent(in) :: flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_),target :: work(:) + type(psb_desc_type), target :: desc_a + integer(psb_ipk_), optional :: data + end subroutine psi_i2swaptranm + subroutine psi_i2swaptranv(flag,beta,y,desc_a,work,info,data) + import + integer(psb_ipk_), intent(in) :: flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_),target :: work(:) + type(psb_desc_type), target :: desc_a + integer(psb_ipk_), optional :: data + end subroutine psi_i2swaptranv + subroutine psi_i2tranidxm(ictxt,icomm,flag,n,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + import + integer(psb_ipk_), intent(in) :: ictxt,icomm,flag, n + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:,:), beta + integer(psb_i2pk_),target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd,totrcv + end subroutine psi_i2tranidxm + subroutine psi_i2tranidxv(ictxt,icomm,flag,beta,y,idx,& + & totxch,totsnd,totrcv,work,info) + import + integer(psb_ipk_), intent(in) :: ictxt,icomm,flag + integer(psb_ipk_), intent(out) :: info + integer(psb_i2pk_) :: y(:), beta + integer(psb_i2pk_),target :: work(:) + integer(psb_ipk_), intent(in) :: idx(:),totxch,totsnd,totrcv + end subroutine psi_i2tranidxv + end interface psi_swaptran + + interface psi_ovrl_upd + subroutine psi_i2ovrl_updr1(x,desc_a,update,info) + import + integer(psb_i2pk_), intent(inout), target :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(in) :: update + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_updr1 + subroutine psi_i2ovrl_updr2(x,desc_a,update,info) + import + integer(psb_i2pk_), intent(inout), target :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(in) :: update + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_updr2 + end interface psi_ovrl_upd + + interface psi_ovrl_save + subroutine psi_i2ovrl_saver1(x,xs,desc_a,info) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_i2pk_), allocatable :: xs(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_saver1 + subroutine psi_i2ovrl_saver2(x,xs,desc_a,info) + import + integer(psb_i2pk_), intent(inout) :: x(:,:) + integer(psb_i2pk_), allocatable :: xs(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_saver2 + end interface psi_ovrl_save + + interface psi_ovrl_restore + subroutine psi_i2ovrl_restrr1(x,xs,desc_a,info) + import + integer(psb_i2pk_), intent(inout) :: x(:) + integer(psb_i2pk_) :: xs(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_restrr1 + subroutine psi_i2ovrl_restrr2(x,xs,desc_a,info) + import + integer(psb_i2pk_), intent(inout) :: x(:,:) + integer(psb_i2pk_) :: xs(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psi_i2ovrl_restrr2 + end interface psi_ovrl_restore + +end module psi_i2_comm_a_mod + diff --git a/base/modules/comm/psi_i_comm_v_mod.f90 b/base/modules/comm/psi_i_comm_v_mod.f90 index 91b2f85a6..bc4ea2a85 100644 --- a/base/modules/comm/psi_i_comm_v_mod.f90 +++ b/base/modules/comm/psi_i_comm_v_mod.f90 @@ -30,7 +30,8 @@ ! ! module psi_i_comm_v_mod - use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, psb_lpk_, psb_epk_ + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, & + & psb_lpk_, psb_epk_, psb_i2pk_ use psb_i_base_vect_mod, only : psb_i_base_vect_type use psb_i_base_multivect_mod, only : psb_i_base_multivect_type diff --git a/base/modules/comm/psi_l_comm_v_mod.f90 b/base/modules/comm/psi_l_comm_v_mod.f90 index 150c5bd45..4c80b0907 100644 --- a/base/modules/comm/psi_l_comm_v_mod.f90 +++ b/base/modules/comm/psi_l_comm_v_mod.f90 @@ -30,7 +30,8 @@ ! ! module psi_l_comm_v_mod - use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, psb_lpk_, psb_epk_ + use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, & + & psb_lpk_, psb_epk_, psb_i2pk_ use psb_desc_mod, only : psb_desc_type, psb_ipk_, psb_mpk_, psb_lpk_, psb_epk_, psb_i_base_vect_type use psb_l_base_vect_mod, only : psb_l_base_vect_type use psb_l_base_multivect_mod, only : psb_l_base_multivect_type diff --git a/base/modules/desc/psb_desc_const_mod.f90 b/base/modules/desc/psb_desc_const_mod.f90 index 8c3937e01..aa2ea2fe0 100644 --- a/base/modules/desc/psb_desc_const_mod.f90 +++ b/base/modules/desc/psb_desc_const_mod.f90 @@ -104,9 +104,17 @@ module psb_desc_const_mod integer(psb_ipk_), parameter :: psb_hash_bits = 16 integer(psb_ipk_), parameter :: psb_max_hash_bits = 22 integer(psb_ipk_), parameter :: psb_hash_size = 2**psb_hash_bits, psb_hash_mask=psb_hash_size-1 - integer(psb_ipk_), parameter :: psb_default_large_threshold=1*1024*1024 integer(psb_ipk_), parameter :: psb_hpnt_nentries_ = 7 - + integer(psb_ipk_), parameter :: psb_default_large_threshold=1*1024*1024 + ! + ! Choice of algorithm for sparse matrix A2AV + ! + integer(psb_ipk_), parameter :: psb_sp_a2av_smpl_triad_ = 1 + integer(psb_ipk_), parameter :: psb_sp_a2av_smpl_v_ = 2 + integer(psb_ipk_), parameter :: psb_sp_a2av_mpi_ = 3 + integer(psb_ipk_), parameter :: psb_sp_a2av_alg_min_ = psb_sp_a2av_smpl_triad_ + integer(psb_ipk_), parameter :: psb_sp_a2av_alg_max_ = psb_sp_a2av_mpi_ + ! ! Constants for desc_a handling ! diff --git a/base/modules/desc/psb_desc_mod.F90 b/base/modules/desc/psb_desc_mod.F90 index fbc64c8cb..43ae58525 100644 --- a/base/modules/desc/psb_desc_mod.F90 +++ b/base/modules/desc/psb_desc_mod.F90 @@ -285,14 +285,6 @@ module psb_desc_mod module procedure psb_cdfree end interface psb_free - interface psb_cd_set_maxspace - module procedure psb_cd_set_maxspace - end interface psb_cd_set_maxspace - - interface psb_cd_get_maxspace - module procedure psb_cd_get_maxspace - end interface psb_cd_get_maxspace - interface psb_cd_set_large_threshold module procedure psb_i_cd_set_large_threshold end interface psb_cd_set_large_threshold @@ -302,7 +294,15 @@ module psb_desc_mod module procedure psb_l_cd_set_large_threshold end interface psb_cd_set_large_threshold #endif - + + interface psb_set_sp_a2av_alg + module procedure psb_m_set_sp_a2av_alg, psb_e_set_sp_a2av_alg + end interface psb_set_sp_a2av_alg + + interface psb_get_sp_a2av_alg + module procedure psb_m_get_sp_a2av_alg + end interface psb_get_sp_a2av_alg + private :: nullify_desc, cd_get_fmt,& & cd_l2gs1, cd_l2gs2, cd_l2gv1, cd_l2gv2, cd_g2ls1,& & cd_g2ls2, cd_g2lv1, cd_g2lv2, cd_g2ls1_ins,& @@ -310,11 +310,33 @@ module psb_desc_mod integer(psb_lpk_), private, save :: cd_large_threshold = psb_default_large_threshold - integer(psb_ipk_), private, save :: cd_maxspace = -1 - + integer(psb_ipk_), private, save :: sp_a2av_alg = psb_sp_a2av_smpl_triad_ contains + function psb_m_get_sp_a2av_alg() result(val) + implicit none + integer(psb_mpk_) :: val + val = sp_a2av_alg + end function psb_m_get_sp_a2av_alg + + subroutine psb_m_set_sp_a2av_alg(val) + implicit none + integer(psb_mpk_), intent(in) :: val + + if ((psb_sp_a2av_alg_min_ <= val).and.(val<=psb_sp_a2av_alg_max_)) & + & sp_a2av_alg = val + end subroutine psb_m_set_sp_a2av_alg + + subroutine psb_e_set_sp_a2av_alg(val) + implicit none + integer(psb_epk_), intent(in) :: val + + if ((psb_sp_a2av_alg_min_ <= val).and.(val<=psb_sp_a2av_alg_max_)) & + & sp_a2av_alg = val + end subroutine psb_e_set_sp_a2av_alg + + function psb_cd_sizeof(desc) result(val) implicit none !....Parameters... @@ -362,21 +384,6 @@ contains integer(psb_lpk_) :: val val = cd_large_threshold end function psb_cd_get_large_threshold - - - subroutine psb_cd_set_maxspace(ith) - implicit none - integer(psb_ipk_), intent(in) :: ith - if (ith > 0) then - cd_maxspace = ith - end if - end subroutine psb_cd_set_maxspace - - function psb_cd_get_maxspace() result(val) - implicit none - integer(psb_ipk_) :: val - val = cd_maxspace - end function psb_cd_get_maxspace function psb_cd_is_large_size(m) result(val) use psb_penv_mod diff --git a/base/modules/desc/psb_gen_block_map_mod.F90 b/base/modules/desc/psb_gen_block_map_mod.F90 index 255b05d11..b53713a5e 100644 --- a/base/modules/desc/psb_gen_block_map_mod.F90 +++ b/base/modules/desc/psb_gen_block_map_mod.F90 @@ -127,7 +127,7 @@ module psb_gen_block_map_mod #if defined(IPK4) && defined(LPK8) private :: l_gen_block_search #endif - + interface gen_block_search module procedure i_gen_block_search #if defined(IPK4) && defined(LPK8) @@ -373,7 +373,7 @@ contains integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: mask(:) logical, intent(in), optional :: owned - integer(psb_ipk_) :: i + integer(psb_lpk_) :: i logical :: owned_ info = 0 @@ -431,7 +431,7 @@ contains integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: mask(:) logical, intent(in), optional :: owned - integer(psb_ipk_) :: is, im, i + integer(psb_lpk_) :: is, im, i logical :: owned_ info = 0 @@ -806,7 +806,7 @@ contains logical, intent(in), optional :: owned integer(psb_ipk_) :: i, nv, is integer(psb_lpk_) :: tidx, ip, lip - integer(psb_mpk_) :: ictxt, iam, np + integer(psb_ipk_) :: ictxt, iam, np logical :: owned_ info = 0 @@ -922,7 +922,7 @@ contains integer(psb_ipk_) :: i, nv, is, im integer(psb_lpk_) :: tidx, ip, lip - integer(psb_mpk_) :: ictxt, iam, np + integer(psb_ipk_) :: ictxt, iam, np logical :: owned_ info = 0 @@ -1527,7 +1527,7 @@ contains logical, intent(in), optional :: mask(:) integer(psb_ipk_), intent(in), optional :: lidx(:) - integer(psb_ipk_) :: i, nv, is, ix + integer(psb_lpk_) :: i, nv, is, ix integer(psb_lpk_) :: ip, lip, lnxt integer(psb_ipk_) :: nxt @@ -1732,7 +1732,7 @@ contains logical, intent(in), optional :: mask(:) integer(psb_ipk_), intent(in), optional :: lidx(:) - integer(psb_ipk_) :: i, nv, is, ix, im + integer(psb_lpk_) :: i, nv, is, ix, im integer(psb_lpk_) :: ip, lip, lnxt integer(psb_ipk_) :: nxt @@ -1964,11 +1964,11 @@ contains use psb_error_mod implicit none class(psb_gen_block_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_ipk_), intent(in) :: nl integer(psb_ipk_), intent(out) :: info ! To be implemented - integer(psb_mpk_) :: iam, np + integer(psb_ipk_) :: iam, np integer(psb_ipk_) :: i integer(psb_lpk_) :: ntot integer(psb_lpk_), allocatable :: vnl(:) @@ -2030,7 +2030,7 @@ contains integer(psb_ipk_), intent(out) :: info integer(psb_ipk_) :: nhal, i - integer(psb_mpk_) :: ictxt, iam, np + integer(psb_ipk_) :: ictxt, iam, np logical :: debug=.false. info = 0 ictxt = idxmap%get_ctxt() diff --git a/base/modules/desc/psb_glist_map_mod.f90 b/base/modules/desc/psb_glist_map_mod.f90 index 3298291a9..69169b173 100644 --- a/base/modules/desc/psb_glist_map_mod.f90 +++ b/base/modules/desc/psb_glist_map_mod.f90 @@ -96,11 +96,11 @@ contains use psb_error_mod implicit none class(psb_glist_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_ipk_), intent(in) :: vg(:) integer(psb_ipk_), intent(out) :: info ! To be implemented - integer(psb_mpk_) :: iam, np + integer(psb_ipk_) :: iam, np integer(psb_ipk_) :: nl integer(psb_lpk_) :: i, n diff --git a/base/modules/desc/psb_hash_map_mod.f90 b/base/modules/desc/psb_hash_map_mod.f90 index 02eff7a4a..ae109d5a5 100644 --- a/base/modules/desc/psb_hash_map_mod.f90 +++ b/base/modules/desc/psb_hash_map_mod.f90 @@ -94,8 +94,8 @@ module psb_hash_map_mod procedure, pass(idxmap) :: lg2lv1_ins => hash_g2lv1_ins procedure, pass(idxmap) :: lg2lv2_ins => hash_g2lv2_ins - procedure, pass(idxmap) :: hash_cpy - generic, public :: assignment(=) => hash_cpy +!!$ procedure, pass(idxmap) :: hash_cpy +!!$ generic, public :: assignment(=) => hash_cpy procedure, pass(idxmap) :: bld_g2l_map => hash_bld_g2l_map end type psb_hash_map @@ -805,11 +805,11 @@ contains use psb_realloc_mod implicit none class(psb_hash_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_lpk_), intent(in) :: vl(:) integer(psb_ipk_), intent(out) :: info ! To be implemented - integer(psb_mpk_) :: iam, np + integer(psb_ipk_) :: iam, np integer(psb_ipk_) :: i, nlu, nl, int_err(5) integer(psb_lpk_) :: m, nrt integer(psb_lpk_), allocatable :: vlu(:) @@ -878,11 +878,11 @@ contains use psb_error_mod implicit none class(psb_hash_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_ipk_), intent(in) :: vg(:) integer(psb_ipk_), intent(out) :: info ! To be implemented - integer(psb_mpk_) :: iam, np + integer(psb_ipk_) :: iam, np integer(psb_ipk_) :: i, j, nl, int_err(5) integer(psb_lpk_) :: n integer(psb_lpk_), allocatable :: vlu(:) @@ -938,12 +938,12 @@ contains use psb_realloc_mod implicit none class(psb_hash_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_lpk_), intent(in) :: vlu(:), ntot integer(psb_ipk_), intent(in) :: nl integer(psb_ipk_), intent(out) :: info ! To be implemented - integer(psb_mpk_) :: iam, np + integer(psb_ipk_) :: iam, np integer(psb_ipk_) :: i, j, lc2, nlu, m, nrt,int_err(5) character(len=20), parameter :: name='hash_map_init_vlu' @@ -1464,7 +1464,7 @@ contains end if select type (outmap) - type is (psb_hash_map) + type is (psb_hash_map) call idxmap%psb_indx_map%cpy(outmap%psb_indx_map,info) if (info == psb_success_) then outmap%hashvsize = idxmap%hashvsize @@ -1478,7 +1478,7 @@ contains & call psb_safe_ab_cpy(idxmap%glb_lc,outmap%glb_lc,info) if (info == psb_success_)& & call psb_hash_copy(idxmap%hash,outmap%hash,info) -!!$ outmap = idxmap + class default ! This should be impossible info = -1 @@ -1499,30 +1499,30 @@ contains end subroutine hash_clone - subroutine hash_cpy(outmap,idxmap) - use psb_penv_mod - use psb_error_mod - use psb_realloc_mod - implicit none - class(psb_hash_map), intent(in) :: idxmap - type(psb_hash_map), intent(out) :: outmap - integer(psb_ipk_) :: info - - info = psb_success_ - outmap%psb_indx_map = idxmap%psb_indx_map - outmap%hashvsize = idxmap%hashvsize - outmap%hashvmask = idxmap%hashvmask - if (info == psb_success_)& - & call psb_safe_ab_cpy(idxmap%loc_to_glob,outmap%loc_to_glob,info) - if (info == psb_success_)& - & call psb_safe_ab_cpy(idxmap%hashv,outmap%hashv,info) - if (info == psb_success_)& - & call psb_safe_ab_cpy(idxmap%glb_lc,outmap%glb_lc,info) - if (info == psb_success_)& - & call psb_hash_copy(idxmap%hash,outmap%hash,info) - end subroutine hash_cpy - - +!!$ subroutine hash_cpy(outmap,idxmap) +!!$ use psb_penv_mod +!!$ use psb_error_mod +!!$ use psb_realloc_mod +!!$ implicit none +!!$ class(psb_hash_map), intent(in) :: idxmap +!!$ type(psb_hash_map), intent(out) :: outmap +!!$ integer(psb_ipk_) :: info +!!$ +!!$ info = psb_success_ +!!$ call idxmap%psb_indx_map%cpy(outmap%psb_indx_map,info) +!!$ if (info == psb_success_) then +!!$ outmap%hashvsize = idxmap%hashvsize +!!$ outmap%hashvmask = idxmap%hashvmask +!!$ end if +!!$ if (info == psb_success_)& +!!$ & call psb_safe_ab_cpy(idxmap%loc_to_glob,outmap%loc_to_glob,info) +!!$ if (info == psb_success_)& +!!$ & call psb_safe_ab_cpy(idxmap%hashv,outmap%hashv,info) +!!$ if (info == psb_success_)& +!!$ & call psb_safe_ab_cpy(idxmap%glb_lc,outmap%glb_lc,info) +!!$ if (info == psb_success_)& +!!$ & call psb_hash_copy(idxmap%hash,outmap%hash,info) +!!$ end subroutine hash_cpy subroutine hash_reinit(idxmap,info) use psb_penv_mod @@ -1534,8 +1534,8 @@ contains integer(psb_ipk_) :: err_act, nr,nc,k, nl integer(psb_lpk_) :: lk integer(psb_lpk_) :: ntot - integer(psb_mpk_) :: ictxt, me, np - integer(psb_ipk_), allocatable :: lidx(:) + integer(psb_ipk_) :: ictxt, me, np + integer(psb_ipk_), allocatable :: lidx(:), tadj(:), th_own(:) integer(psb_lpk_), allocatable :: gidx(:) character(len=20) :: name='hash_reinit' logical, parameter :: debug=.false. @@ -1551,13 +1551,16 @@ contains lidx = (/(k,k=1,nc)/) gidx = (/(lk,lk=1,nc)/) call idxmap%l2gip(gidx,info) - + tadj = idxmap%get_p_adjcncy() + call idxmap%get_halo_owner(th_own,info) + call idxmap%free() call hash_init_vlu(idxmap,ictxt,ntot,nr,gidx(1:nr),info) if (nc>nr) then call idxmap%g2lip_ins(gidx(nr+1:nc),info,lidx=lidx(nr+1:nc)) end if - + call idxmap%set_p_adjcncy(tadj) + call idxmap%set_halo_owner(th_own,info) if (info /= psb_success_) then info = psb_err_from_subroutine_ diff --git a/base/modules/desc/psb_hash_mod.F90 b/base/modules/desc/psb_hash_mod.F90 index 76c02fc5b..42911e3ff 100644 --- a/base/modules/desc/psb_hash_mod.F90 +++ b/base/modules/desc/psb_hash_mod.F90 @@ -64,8 +64,11 @@ module psb_hash_mod end type psb_hash_type - integer(psb_ipk_), parameter :: HashDuplicate = 123, HashOK=0, HashOutOfMemory=-512,& - & HashFreeEntry = -1, HashNotFound = -256 + integer(psb_ipk_), parameter :: HashOK=0 + integer(psb_ipk_), parameter :: HashDuplicate = 123 + integer(psb_ipk_), parameter :: HashOutOfMemory=-512 + integer(psb_ipk_), parameter :: HashFreeEntry = -1 + integer(psb_ipk_), parameter :: HashNotFound = -256 interface psb_hashval #if defined(IPK4) @@ -391,7 +394,7 @@ contains hd = 1 else hd = hsize - hk - hd = ior(hd,1) + hd = ior(hd,1_psb_ipk_) end if if (.not.allocated(hash%table)) then info = HashOutOfMemory @@ -451,7 +454,7 @@ contains hd = 1 else hd = hsize - hk - hd = ior(hd,1) + hd = ior(hd,1_psb_ipk_) end if if (.not.allocated(hash%table)) then info = HashOutOfMemory @@ -515,7 +518,7 @@ contains hd = 1 else hd = hsize - hk - hd = ior(hd,1) + hd = ior(hd,1_psb_ipk_) end if hash%nsrch = hash%nsrch + 1 @@ -555,7 +558,7 @@ contains hd = 1 else hd = hsize - hk - hd = ior(hd,1) + hd = ior(hd,1_psb_ipk_) end if hash%nsrch = hash%nsrch + 1 diff --git a/base/modules/desc/psb_indx_map_mod.f90 b/base/modules/desc/psb_indx_map_mod.f90 index 378b38afe..710e2ea9f 100644 --- a/base/modules/desc/psb_indx_map_mod.f90 +++ b/base/modules/desc/psb_indx_map_mod.f90 @@ -29,7 +29,7 @@ ! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! POSSIBILITY OF SUCH DAMAGE. ! -!!$ +! ! ! ! package: psb_indx_map_mod @@ -108,7 +108,7 @@ module psb_indx_map_mod !> State of the map integer(psb_ipk_) :: state = psb_desc_null_ !> Communication context - integer(psb_mpk_) :: ictxt = -1 + integer(psb_ipk_) :: ictxt = -1 !> MPI communicator integer(psb_mpk_) :: mpic = -1 !> Number of global rows @@ -278,13 +278,14 @@ module psb_indx_map_mod end interface interface - subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info) + subroutine psi_a2a_fnd_owner(idx,iprc,idxmap,info,samesize) import :: psb_indx_map, psb_ipk_, psb_lpk_ implicit none integer(psb_lpk_), intent(in) :: idx(:) integer(psb_ipk_), allocatable, intent(out) :: iprc(:) class(psb_indx_map), intent(in) :: idxmap integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: samesize end subroutine psi_a2a_fnd_owner end interface @@ -311,6 +312,25 @@ module psb_indx_map_mod end subroutine psi_graph_fnd_owner end interface + interface psb_cd_set_maxspace + module procedure psb_cd_set_maxspace + end interface psb_cd_set_maxspace + + interface psb_cd_get_maxspace + module procedure psb_cd_get_maxspace + end interface psb_cd_get_maxspace + + interface psb_cd_set_samplesize + module procedure psb_cd_set_samplesize + end interface psb_cd_set_samplesize + + interface psb_cd_get_samplesize + module procedure psb_cd_get_samplesize + end interface psb_cd_get_samplesize + + integer(psb_ipk_), private, save :: cd_maxspace = -1 + integer(psb_ipk_), private, save :: samplesize = 32 + integer, parameter :: psi_symm_flag_norv_ = 0 integer, parameter :: psi_symm_flag_inrv_ = 1 interface psi_symm_dep_list @@ -331,9 +351,69 @@ module psb_indx_map_mod end subroutine psi_symm_dep_list_norv end interface psi_symm_dep_list + integer(psb_mpk_), parameter :: psi_adj_fnd_irecv_ = 0 + integer(psb_mpk_), parameter :: psi_adj_fnd_a2av_ = 1 + integer(psb_mpk_), parameter :: psi_adj_fnd_pbrcv_ = 2 + integer(psb_mpk_), parameter :: psi_adj_alg_max_ = psi_adj_fnd_pbrcv_ + integer(psb_mpk_), save :: psi_adj_alg = psi_adj_fnd_irecv_ + contains + subroutine psi_set_adj_alg(ialg) + integer(psb_mpk_), intent(in) :: ialg + if ((ialg >=0) .and. (ialg <= psi_adj_alg_max_))& + & psi_adj_alg = ialg + end subroutine psi_set_adj_alg + function psi_get_adj_alg() result(val) + integer(psb_mpk_) :: val + val = psi_adj_alg + end function psi_get_adj_alg + + function psi_get_adj_alg_fmt() result(val) + character(len=20) :: val + select case(psi_adj_alg) + case(psi_adj_fnd_a2av_) + val = 'MPI_A2AV' + case(psi_adj_fnd_irecv_) + val = 'MPI_ISEND/IRECV' + case(psi_adj_fnd_pbrcv_) + val = 'PSB_SND/RCV' + case default + val = 'Unknown ?' + end select + end function psi_get_adj_alg_fmt + + subroutine psb_cd_set_maxspace(ith) + implicit none + integer(psb_ipk_), intent(in) :: ith + if (ith > 0) then + cd_maxspace = ith + end if + end subroutine psb_cd_set_maxspace + + function psb_cd_get_maxspace() result(val) + implicit none + integer(psb_ipk_) :: val + val = cd_maxspace + end function psb_cd_get_maxspace + + + subroutine psb_cd_set_samplesize(ith) + implicit none + integer(psb_ipk_), intent(in) :: ith + if (ith > 0) then + samplesize = ith + end if + end subroutine psb_cd_set_samplesize + + function psb_cd_get_samplesize() result(val) + implicit none + integer(psb_ipk_) :: val + val = samplesize + end function psb_cd_get_samplesize + + !> !! \memberof psb_indx_map !! \brief Print a descriptive name @@ -407,7 +487,7 @@ contains function base_get_ctxt(idxmap) result(val) implicit none class(psb_indx_map), intent(in) :: idxmap - integer(psb_mpk_) :: val + integer(psb_ipk_) :: val val = idxmap%ictxt @@ -435,7 +515,7 @@ contains subroutine base_set_ctxt(idxmap,val) implicit none class(psb_indx_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: val + integer(psb_ipk_), intent(in) :: val idxmap%ictxt = val end subroutine base_set_ctxt @@ -1268,7 +1348,7 @@ contains use psb_error_mod implicit none class(psb_indx_map), intent(inout) :: idxmap - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_lpk_), intent(in) :: vl(:) integer(psb_ipk_), intent(out) :: info integer(psb_ipk_) :: err_act @@ -1390,7 +1470,7 @@ contains integer(psb_ipk_), intent(in) :: v(:) integer(psb_ipk_), intent(out) :: info ! - integer(psb_mpk_) :: me, np + integer(psb_ipk_) :: me, np integer(psb_ipk_) :: i, j, nr, nc, nh call psb_info(idxmap%ictxt,me,np) @@ -1406,6 +1486,7 @@ contains end subroutine base_set_halo_owner subroutine base_get_halo_owner(idxmap,v,info) + use psb_realloc_mod use psb_penv_mod use psb_error_mod implicit none @@ -1414,13 +1495,15 @@ contains integer(psb_ipk_), intent(out) :: info integer(psb_ipk_) :: nh - nh = min(size(v),size(idxmap%halo_owner)) - v(1:nh) = idxmap%halo_owner(1:nh) + nh = size(idxmap%halo_owner) + !v = idxmap%halo_owner(1:nh) + call psb_safe_ab_cpy(idxmap%halo_owner,v,info) end subroutine base_get_halo_owner subroutine base_fnd_halo_owner_s(idxmap,xin,xout,info) use psb_penv_mod use psb_error_mod + use psb_realloc_mod implicit none class(psb_indx_map), intent(inout) :: idxmap integer(psb_ipk_), intent(in) :: xin @@ -1430,16 +1513,17 @@ contains integer(psb_ipk_) :: i, j, nr, nc, nh nr = idxmap%local_rows nc = idxmap%local_cols + nc = min(idxmap%local_cols, (nr+psb_size(idxmap%halo_owner))) xout = -1 if (.not.allocated(idxmap%halo_owner)) then !write(0,*) 'Halo_owner not allocated!', nr, nc, xin return end if if ((nr 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_c_simple_a2av + + subroutine psb_c_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + complex(psb_spk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + complex(psb_spk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_complex_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_c_spk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_complex_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_c_spk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_c_m_simple_triad_a2av + + subroutine psb_c_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + complex(psb_spk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + complex(psb_spk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_complex_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_c_spk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_complex_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_c_e_simple_triad_a2av + end module psi_c_collective_mod diff --git a/base/modules/penv/psi_d_collective_mod.F90 b/base/modules/penv/psi_d_collective_mod.F90 index fa022233d..eb848a9fe 100644 --- a/base/modules/penv/psi_d_collective_mod.F90 +++ b/base/modules/penv/psi_d_collective_mod.F90 @@ -31,6 +31,7 @@ ! module psi_d_collective_mod use psi_penv_mod + use psi_comm_buffers_mod interface psb_max module procedure psb_dmaxs, psb_dmaxv, psb_dmaxm, & @@ -76,7 +77,13 @@ module psi_d_collective_mod module procedure psb_dexscan_sums, psb_dexscan_sumv end interface psb_exscan_sum + interface psb_simple_a2av + module procedure psb_d_simple_a2av + end interface psb_simple_a2av + interface psb_simple_triad_a2av + module procedure psb_d_e_simple_triad_a2av, psb_d_m_simple_triad_a2av + end interface psb_simple_triad_a2av contains @@ -1255,16 +1262,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_dpk_), intent(inout) :: dat real(psb_dpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_scan(dat,dat_,1,psb_mpi_r_dpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_r_dpk_,mpi_sum,icomm,minfo) dat = dat_ #endif end subroutine psb_dscan_sums @@ -1278,16 +1286,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_dpk_), intent(inout) :: dat real(psb_dpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_exscan(dat,dat_,1,psb_mpi_r_dpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_r_dpk_,mpi_sum,icomm,minfo) dat = dat_ #else dat = dzero @@ -1303,20 +1312,21 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_dpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ real(psb_dpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_scan(dat,dat_,size(dat),psb_mpi_r_dpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_r_dpk_,mpi_sum,icomm,minfo) #endif end subroutine psb_dscan_sumv @@ -1329,23 +1339,228 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_dpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ real(psb_dpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_exscan(dat,dat_,size(dat),psb_mpi_r_dpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_r_dpk_,mpi_sum,icomm,minfo) #else dat = dzero #endif end subroutine psb_dexscan_sumv + + subroutine psb_d_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_d_p2p_mod + implicit none + real(psb_dpk_), intent(in) :: valsnd(:) + real(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_d_simple_a2av + + subroutine psb_d_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + real(psb_dpk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + real(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_double_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_double_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_d_m_simple_triad_a2av + + subroutine psb_d_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + real(psb_dpk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + real(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_double_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_double_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_d_e_simple_triad_a2av + end module psi_d_collective_mod diff --git a/base/modules/penv/psi_e_collective_mod.F90 b/base/modules/penv/psi_e_collective_mod.F90 index 59e74280a..4c3a006ed 100644 --- a/base/modules/penv/psi_e_collective_mod.F90 +++ b/base/modules/penv/psi_e_collective_mod.F90 @@ -31,6 +31,7 @@ ! module psi_e_collective_mod use psi_penv_mod + use psi_comm_buffers_mod interface psb_max module procedure psb_emaxs, psb_emaxv, psb_emaxm, & @@ -72,7 +73,13 @@ module psi_e_collective_mod module procedure psb_eexscan_sums, psb_eexscan_sumv end interface psb_exscan_sum + interface psb_simple_a2av + module procedure psb_e_simple_a2av + end interface psb_simple_a2av + interface psb_simple_triad_a2av + module procedure psb_e_e_simple_triad_a2av, psb_e_m_simple_triad_a2av + end interface psb_simple_triad_a2av contains @@ -1132,16 +1139,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_epk_), intent(inout) :: dat integer(psb_epk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_scan(dat,dat_,1,psb_mpi_epk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_epk_,mpi_sum,icomm,minfo) dat = dat_ #endif end subroutine psb_escan_sums @@ -1155,16 +1163,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_epk_), intent(inout) :: dat integer(psb_epk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_exscan(dat,dat_,1,psb_mpi_epk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_epk_,mpi_sum,icomm,minfo) dat = dat_ #else dat = ezero @@ -1180,20 +1189,21 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_epk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ integer(psb_epk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_scan(dat,dat_,size(dat),psb_mpi_epk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_epk_,mpi_sum,icomm,minfo) #endif end subroutine psb_escan_sumv @@ -1206,23 +1216,228 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_epk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ integer(psb_epk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_exscan(dat,dat_,size(dat),psb_mpi_epk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_epk_,mpi_sum,icomm,minfo) #else dat = ezero #endif end subroutine psb_eexscan_sumv + + subroutine psb_e_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_e_p2p_mod + implicit none + integer(psb_epk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_e_simple_a2av + + subroutine psb_e_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_epk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_epk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int8_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int8_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_e_m_simple_triad_a2av + + subroutine psb_e_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_epk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_epk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int8_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int8_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_e_e_simple_triad_a2av + end module psi_e_collective_mod diff --git a/base/modules/penv/psi_i2_collective_mod.F90 b/base/modules/penv/psi_i2_collective_mod.F90 new file mode 100644 index 000000000..911ed9386 --- /dev/null +++ b/base/modules/penv/psi_i2_collective_mod.F90 @@ -0,0 +1,1443 @@ +! +! 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. +! +! +module psi_i2_collective_mod + use psi_penv_mod + use psi_comm_buffers_mod + + interface psb_max + module procedure psb_i2maxs, psb_i2maxv, psb_i2maxm, & + & psb_i2maxs_ec, psb_i2maxv_ec, psb_i2maxm_ec + end interface + + interface psb_min + module procedure psb_i2mins, psb_i2minv, psb_i2minm, & + & psb_i2mins_ec, psb_i2minv_ec, psb_i2minm_ec + end interface psb_min + + + interface psb_sum + module procedure psb_i2sums, psb_i2sumv, psb_i2summ, & + & psb_i2sums_ec, psb_i2sumv_ec, psb_i2summ_ec + end interface + + interface psb_amx + module procedure psb_i2amxs, psb_i2amxv, psb_i2amxm, & + & psb_i2amxs_ec, psb_i2amxv_ec, psb_i2amxm_ec + end interface + + interface psb_amn + module procedure psb_i2amns, psb_i2amnv, psb_i2amnm, & + & psb_i2amns_ec, psb_i2amnv_ec, psb_i2amnm_ec + end interface + + + interface psb_bcast + module procedure psb_i2bcasts, psb_i2bcastv, psb_i2bcastm, & + & psb_i2bcasts_ec, psb_i2bcastv_ec, psb_i2bcastm_ec + end interface psb_bcast + + interface psb_scan_sum + module procedure psb_i2scan_sums, psb_i2scan_sumv + end interface psb_scan_sum + + interface psb_exscan_sum + module procedure psb_i2exscan_sums, psb_i2exscan_sumv + end interface psb_exscan_sum + + interface psb_simple_a2av + module procedure psb_i2_simple_a2av + end interface psb_simple_a2av + + interface psb_simple_triad_a2av + module procedure psb_i2_e_simple_triad_a2av, psb_i2_m_simple_triad_a2av + end interface psb_simple_triad_a2av + + +contains + + ! !!!!!!!!!!!!!!!!!!!!!! + ! + ! Reduction operations + ! + ! !!!!!!!!!!!!!!!!!!!!!! + + + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! + ! MAX + ! + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + subroutine psb_i2maxs(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_) :: dat_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call mpi_allreduce(dat,dat_,1,psb_mpi_i2pk_,mpi_max,ictxt,info) + dat = dat_ + else + call mpi_reduce(dat,dat_,1,psb_mpi_i2pk_,mpi_max,root_,ictxt,info) + if (iam == root_) dat = dat_ + endif +#endif + end subroutine psb_i2maxs + + subroutine psb_i2maxv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_) & + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_max,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_max,root_,ictxt,info) + else + call psb_realloc(1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_max,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2maxv + + subroutine psb_i2maxm(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:,:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_)& + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_max,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_max,root_,ictxt,info) + else + call psb_realloc(1,1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_max,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2maxm + + + subroutine psb_i2maxs_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_max(ictxt_,dat,root_) + else + call psb_max(ictxt_,dat) + end if + end subroutine psb_i2maxs_ec + + subroutine psb_i2maxv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_max(ictxt_,dat,root_) + else + call psb_max(ictxt_,dat) + end if + end subroutine psb_i2maxv_ec + + subroutine psb_i2maxm_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_max(ictxt_,dat,root_) + else + call psb_max(ictxt_,dat) + end if + end subroutine psb_i2maxm_ec + + + ! + ! MIN: Minimum Value + ! + + + subroutine psb_i2mins(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_) :: dat_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call mpi_allreduce(dat,dat_,1,psb_mpi_i2pk_,mpi_min,ictxt,info) + dat = dat_ + else + call mpi_reduce(dat,dat_,1,psb_mpi_i2pk_,mpi_min,root_,ictxt,info) + if (iam == root_) dat = dat_ + endif +#endif + end subroutine psb_i2mins + + subroutine psb_i2minv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_) & + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_min,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_min,root_,ictxt,info) + else + call psb_realloc(1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_min,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2minv + + subroutine psb_i2minm(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:,:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_)& + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_min,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_min,root_,ictxt,info) + else + call psb_realloc(1,1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_min,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2minm + + + subroutine psb_i2mins_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_min(ictxt_,dat,root_) + else + call psb_min(ictxt_,dat) + end if + end subroutine psb_i2mins_ec + + subroutine psb_i2minv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_min(ictxt_,dat,root_) + else + call psb_min(ictxt_,dat) + end if + end subroutine psb_i2minv_ec + + subroutine psb_i2minm_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_min(ictxt_,dat,root_) + else + call psb_min(ictxt_,dat) + end if + end subroutine psb_i2minm_ec + + + + + ! + ! SUM + ! + + subroutine psb_i2sums(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_) :: dat_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call mpi_allreduce(dat,dat_,1,psb_mpi_i2pk_,mpi_sum,ictxt,info) + dat = dat_ + else + call mpi_reduce(dat,dat_,1,psb_mpi_i2pk_,mpi_sum,root_,ictxt,info) + if (iam == root_) dat = dat_ + endif +#endif + end subroutine psb_i2sums + + subroutine psb_i2sumv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_) & + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_sum,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_sum,root_,ictxt,info) + else + call psb_realloc(1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_sum,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2sumv + + subroutine psb_i2summ(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:,:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_)& + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_sum,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_sum,root_,ictxt,info) + else + call psb_realloc(1,1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_sum,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2summ + + subroutine psb_i2sums_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_sum(ictxt_,dat,root_) + else + call psb_sum(ictxt_,dat) + end if + end subroutine psb_i2sums_ec + + subroutine psb_i2sumv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_sum(ictxt_,dat,root_) + else + call psb_sum(ictxt_,dat) + end if + end subroutine psb_i2sumv_ec + + subroutine psb_i2summ_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_sum(ictxt_,dat,root_) + else + call psb_sum(ictxt_,dat) + end if + end subroutine psb_i2summ_ec + + + ! + ! AMX: Maximum Absolute Value + ! + + subroutine psb_i2amxs(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_) :: dat_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call mpi_allreduce(dat,dat_,1,psb_mpi_i2pk_,mpi_i2amx_op,ictxt,info) + dat = dat_ + else + call mpi_reduce(dat,dat_,1,psb_mpi_i2pk_,mpi_i2amx_op,root_,ictxt,info) + if (iam == root_) dat = dat_ + endif +#endif + end subroutine psb_i2amxs + + subroutine psb_i2amxv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_) & + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,root_,ictxt,info) + else + call psb_realloc(1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2amxv + + subroutine psb_i2amxm(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:,:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_)& + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,root_,ictxt,info) + else + call psb_realloc(1,1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_i2amx_op,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2amxm + + + subroutine psb_i2amxs_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amx(ictxt_,dat,root_) + else + call psb_amx(ictxt_,dat) + end if + end subroutine psb_i2amxs_ec + + subroutine psb_i2amxv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amx(ictxt_,dat,root_) + else + call psb_amx(ictxt_,dat) + end if + end subroutine psb_i2amxv_ec + + subroutine psb_i2amxm_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amx(ictxt_,dat,root_) + else + call psb_amx(ictxt_,dat) + end if + end subroutine psb_i2amxm_ec + + + ! + ! AMN: Minimum Absolute Value + ! + + subroutine psb_i2amns(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_) :: dat_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call mpi_allreduce(dat,dat_,1,psb_mpi_i2pk_,mpi_i2amn_op,ictxt,info) + dat = dat_ + else + call mpi_reduce(dat,dat_,1,psb_mpi_i2pk_,mpi_i2amn_op,root_,ictxt,info) + if (iam == root_) dat = dat_ + endif +#endif + end subroutine psb_i2amns + + subroutine psb_i2amnv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_) & + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,root_,ictxt,info) + else + call psb_realloc(1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2amnv + + subroutine psb_i2amnm(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:,:) + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = -1 + endif + if (root_ == -1) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + if (iinfo == psb_success_)& + & call mpi_allreduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,ictxt,info) + else + if (iam == root_) then + call psb_realloc(size(dat,1),size(dat,2),dat_,iinfo) + dat_ = dat + call mpi_reduce(dat_,dat,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,root_,ictxt,info) + else + call psb_realloc(1,1,dat_,iinfo) + call mpi_reduce(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_i2amn_op,root_,ictxt,info) + end if + endif +#endif + end subroutine psb_i2amnm + + + subroutine psb_i2amns_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amn(ictxt_,dat,root_) + else + call psb_amn(ictxt_,dat) + end if + end subroutine psb_i2amns_ec + + subroutine psb_i2amnv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amn(ictxt_,dat,root_) + else + call psb_amn(ictxt_,dat) + end if + end subroutine psb_i2amnv_ec + + subroutine psb_i2amnm_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_amn(ictxt_,dat,root_) + else + call psb_amn(ictxt_,dat) + end if + end subroutine psb_i2amnm_ec + + + ! + ! BCAST Broadcast + ! + + subroutine psb_i2bcasts(ictxt,dat,root) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = psb_root_ + endif + call mpi_bcast(dat,1,psb_mpi_i2pk_,root_,ictxt,info) + +#endif + end subroutine psb_i2bcasts + + subroutine psb_i2bcastv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = psb_root_ + endif + + call mpi_bcast(dat,size(dat),psb_mpi_i2pk_,root_,ictxt,info) +#endif + end subroutine psb_i2bcastv + + subroutine psb_i2bcastm(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_mpk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + + integer(psb_mpk_) :: iam, np, info + integer(psb_ipk_) :: iinfo + +#if !defined(SERIAL_MPI) + + call psb_info(ictxt,iam,np) + + if (present(root)) then + root_ = root + else + root_ = psb_root_ + endif + + call mpi_bcast(dat,size(dat),psb_mpi_i2pk_,root_,ictxt,info) +#endif + end subroutine psb_i2bcastm + + + subroutine psb_i2bcasts_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_bcast(ictxt_,dat,root_) + else + call psb_bcast(ictxt_,dat) + end if + end subroutine psb_i2bcasts_ec + + subroutine psb_i2bcastv_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_bcast(ictxt_,dat,root_) + else + call psb_bcast(ictxt_,dat) + end if + end subroutine psb_i2bcastv_ec + + subroutine psb_i2bcastm_ec(ictxt,dat,root) + implicit none + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:,:) + integer(psb_epk_), intent(in), optional :: root + integer(psb_mpk_) :: ictxt_, root_ + + ictxt_ = ictxt + if (present(root)) then + root_ = root + call psb_bcast(ictxt_,dat,root_) + else + call psb_bcast(ictxt_,dat) + end if + end subroutine psb_i2bcastm_ec + + + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! + ! SCAN + ! + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + subroutine psb_i2scan_sums(ictxt,dat) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_i2pk_) :: dat_ + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_i2pk_,mpi_sum,icomm,minfo) + dat = dat_ +#endif + end subroutine psb_i2scan_sums + + + subroutine psb_i2exscan_sums(ictxt,dat) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat + integer(psb_i2pk_) :: dat_ + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo + + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_i2pk_,mpi_sum,icomm,minfo) + dat = dat_ +#else + dat = i2zero +#endif + end subroutine psb_i2exscan_sums + + subroutine psb_i2scan_sumv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_ipk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) + dat_ = dat + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_sum,icomm,minfo) +#endif + end subroutine psb_i2scan_sumv + + subroutine psb_i2exscan_sumv(ictxt,dat,root) + use psb_realloc_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(inout) :: dat(:) + integer(psb_ipk_), intent(in), optional :: root + integer(psb_mpk_) :: root_ + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm + +#if !defined(SERIAL_MPI) + call psb_info(ictxt,iam,np) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) + dat_ = dat + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_i2pk_,mpi_sum,icomm,minfo) +#else + dat = i2zero +#endif + end subroutine psb_i2exscan_sumv + + subroutine psb_i2_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_i2_p2p_mod + implicit none + integer(psb_i2pk_), intent(in) :: valsnd(:) + integer(psb_i2pk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_i2_simple_a2av + + subroutine psb_i2_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_i2pk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_i2pk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int2_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_i2pk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int2_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_i2pk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_i2_m_simple_triad_a2av + + subroutine psb_i2_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_i2pk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_i2pk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int2_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_i2pk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int2_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_i2_e_simple_triad_a2av + + +end module psi_i2_collective_mod diff --git a/base/modules/penv/psi_i2_p2p_mod.F90 b/base/modules/penv/psi_i2_p2p_mod.F90 new file mode 100644 index 000000000..84bf7712d --- /dev/null +++ b/base/modules/penv/psi_i2_p2p_mod.F90 @@ -0,0 +1,307 @@ +! +! 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. +! +! + +module psi_i2_p2p_mod + use psi_penv_mod + use psi_comm_buffers_mod + + interface psb_snd + module procedure psb_i2snds, psb_i2sndv, psb_i2sndm, & + & psb_i2snds_ec, psb_i2sndv_ec, psb_i2sndm_ec + end interface + + interface psb_rcv + module procedure psb_i2rcvs, psb_i2rcvv, psb_i2rcvm, & + & psb_i2rcvs_ec, psb_i2rcvv_ec, psb_i2rcvm_ec + end interface + +contains + + subroutine psb_i2snds(ictxt,dat,dst) + use psi_comm_buffers_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat + integer(psb_mpk_), intent(in) :: dst + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: info +#if defined(SERIAL_MPI) + ! do nothing +#else + allocate(dat_(1), stat=info) + dat_(1) = dat + call psi_snd(ictxt,psb_int2_tag,dst,dat_,psb_mesg_queue) +#endif + end subroutine psb_i2snds + + subroutine psb_i2sndv(ictxt,dat,dst) + use psi_comm_buffers_mod + +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat(:) + integer(psb_mpk_), intent(in) :: dst + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: info + +#if defined(SERIAL_MPI) +#else + allocate(dat_(size(dat)), stat=info) + dat_(:) = dat(:) + call psi_snd(ictxt,psb_int2_tag,dst,dat_,psb_mesg_queue) +#endif + + end subroutine psb_i2sndv + + subroutine psb_i2sndm(ictxt,dat,dst,m) + use psi_comm_buffers_mod + +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat(:,:) + integer(psb_mpk_), intent(in) :: dst + integer(psb_ipk_), intent(in), optional :: m + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_ipk_) :: i,j,k,m_,n_ + integer(psb_mpk_) :: info + +#if defined(SERIAL_MPI) +#else + if (present(m)) then + m_ = m + else + m_ = size(dat,1) + end if + n_ = size(dat,2) + allocate(dat_(m_*n_), stat=info) + k=1 + do j=1,n_ + do i=1, m_ + dat_(k) = dat(i,j) + k = k + 1 + end do + end do + call psi_snd(ictxt,psb_int2_tag,dst,dat_,psb_mesg_queue) +#endif + end subroutine psb_i2sndm + + subroutine psb_i2rcvs(ictxt,dat,src) + use psi_comm_buffers_mod +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat + integer(psb_mpk_), intent(in) :: src + integer(psb_mpk_) :: info + integer(psb_mpk_) :: status(mpi_status_size) +#if defined(SERIAL_MPI) + ! do nothing +#else + call mpi_recv(dat,1,psb_mpi_i2pk_,src,psb_int2_tag,ictxt,status,info) + call psb_test_nodes(psb_mesg_queue) +#endif + end subroutine psb_i2rcvs + + subroutine psb_i2rcvv(ictxt,dat,src) + use psi_comm_buffers_mod + +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat(:) + integer(psb_mpk_), intent(in) :: src + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: info + integer(psb_mpk_) :: status(mpi_status_size) +#if defined(SERIAL_MPI) +#else + call mpi_recv(dat,size(dat),psb_mpi_i2pk_,src,psb_int2_tag,ictxt,status,info) + call psb_test_nodes(psb_mesg_queue) +#endif + + end subroutine psb_i2rcvv + + subroutine psb_i2rcvm(ictxt,dat,src,m) + use psi_comm_buffers_mod + +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat(:,:) + integer(psb_mpk_), intent(in) :: src + integer(psb_ipk_), intent(in), optional :: m + integer(psb_i2pk_), allocatable :: dat_(:) + integer(psb_mpk_) :: info ,m_,n_, ld, mp_rcv_type + integer(psb_mpk_) :: i,j,k + integer(psb_mpk_) :: status(mpi_status_size) +#if defined(SERIAL_MPI) + ! What should we do here?? +#else + if (present(m)) then + m_ = m + ld = size(dat,1) + n_ = size(dat,2) + call mpi_type_vector(n_,m_,ld,psb_mpi_i2pk_,mp_rcv_type,info) + if (info == mpi_success) call mpi_type_commit(mp_rcv_type,info) + if (info == mpi_success) call mpi_recv(dat,1,mp_rcv_type,src,& + & psb_int2_tag,ictxt,status,info) + if (info == mpi_success) call mpi_type_free(mp_rcv_type,info) + else + call mpi_recv(dat,size(dat),psb_mpi_i2pk_,src,psb_int2_tag,ictxt,status,info) + end if + if (info /= mpi_success) then + write(psb_err_unit,*) 'Error in psb_recv', info + end if + call psb_test_nodes(psb_mesg_queue) +#endif + end subroutine psb_i2rcvm + + + subroutine psb_i2snds_ec(ictxt,dat,dst) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat + integer(psb_epk_), intent(in) :: dst + + integer(psb_mpk_) :: iictxt, idst + + iictxt = ictxt + idst = dst + call psb_snd(iictxt, dat, idst) + + end subroutine psb_i2snds_ec + + subroutine psb_i2sndv_ec(ictxt,dat,dst) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat(:) + integer(psb_epk_), intent(in) :: dst + + integer(psb_mpk_) :: iictxt, idst + + iictxt = ictxt + idst = dst + call psb_snd(iictxt, dat, idst) + + end subroutine psb_i2sndv_ec + + subroutine psb_i2sndm_ec(ictxt,dat,dst,m) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(in) :: dat(:,:) + integer(psb_epk_), intent(in) :: dst + + integer(psb_mpk_) :: iictxt, idst + + iictxt = ictxt + idst = dst + call psb_snd(iictxt, dat, idst) + + end subroutine psb_i2sndm_ec + + subroutine psb_i2rcvs_ec(ictxt,dat,src) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat + integer(psb_epk_), intent(in) :: src + + integer(psb_mpk_) :: iictxt, isrc + + iictxt = ictxt + isrc = src + call psb_rcv(iictxt, dat, isrc) + + end subroutine psb_i2rcvs_ec + + subroutine psb_i2rcvv_ec(ictxt,dat,src) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat(:) + integer(psb_epk_), intent(in) :: src + + integer(psb_mpk_) :: iictxt, isrc + + iictxt = ictxt + isrc = src + call psb_rcv(iictxt, dat, isrc) + + end subroutine psb_i2rcvv_ec + + subroutine psb_i2rcvm_ec(ictxt,dat,src,m) + + integer(psb_epk_), intent(in) :: ictxt + integer(psb_i2pk_), intent(out) :: dat(:,:) + integer(psb_epk_), intent(in) :: src + + integer(psb_mpk_) :: iictxt, isrc + + iictxt = ictxt + isrc = src + call psb_rcv(iictxt, dat, isrc) + + end subroutine psb_i2rcvm_ec + + +end module psi_i2_p2p_mod diff --git a/base/modules/penv/psi_m_collective_mod.F90 b/base/modules/penv/psi_m_collective_mod.F90 index 5959e468e..206b15fa4 100644 --- a/base/modules/penv/psi_m_collective_mod.F90 +++ b/base/modules/penv/psi_m_collective_mod.F90 @@ -31,6 +31,7 @@ ! module psi_m_collective_mod use psi_penv_mod + use psi_comm_buffers_mod interface psb_max module procedure psb_mmaxs, psb_mmaxv, psb_mmaxm, & @@ -72,7 +73,13 @@ module psi_m_collective_mod module procedure psb_mexscan_sums, psb_mexscan_sumv end interface psb_exscan_sum + interface psb_simple_a2av + module procedure psb_m_simple_a2av + end interface psb_simple_a2av + interface psb_simple_triad_a2av + module procedure psb_m_e_simple_triad_a2av, psb_m_m_simple_triad_a2av + end interface psb_simple_triad_a2av contains @@ -1132,16 +1139,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_mpk_), intent(inout) :: dat integer(psb_mpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_scan(dat,dat_,1,psb_mpi_mpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_mpk_,mpi_sum,icomm,minfo) dat = dat_ #endif end subroutine psb_mscan_sums @@ -1155,16 +1163,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_mpk_), intent(inout) :: dat integer(psb_mpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_exscan(dat,dat_,1,psb_mpi_mpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_mpk_,mpi_sum,icomm,minfo) dat = dat_ #else dat = mzero @@ -1180,20 +1189,21 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_mpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ integer(psb_mpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_scan(dat,dat_,size(dat),psb_mpi_mpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_mpk_,mpi_sum,icomm,minfo) #endif end subroutine psb_mscan_sumv @@ -1206,23 +1216,228 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt integer(psb_mpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ integer(psb_mpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_exscan(dat,dat_,size(dat),psb_mpi_mpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_mpk_,mpi_sum,icomm,minfo) #else dat = mzero #endif end subroutine psb_mexscan_sumv + + subroutine psb_m_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_m_p2p_mod + implicit none + integer(psb_mpk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_m_simple_a2av + + subroutine psb_m_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_mpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int4_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int4_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_m_m_simple_triad_a2av + + subroutine psb_m_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + integer(psb_mpk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + integer(psb_mpk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_int4_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_int4_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_m_e_simple_triad_a2av + end module psi_m_collective_mod diff --git a/base/modules/penv/psi_penv_mod.F90 b/base/modules/penv/psi_penv_mod.F90 index 4d7be8086..a082ea0e2 100644 --- a/base/modules/penv/psi_penv_mod.F90 +++ b/base/modules/penv/psi_penv_mod.F90 @@ -75,8 +75,15 @@ module psi_penv_mod interface psb_wtime module procedure psb_wtime - end interface + end interface psb_wtime + interface psb_get_mpi_comm + module procedure psb_m_get_mpi_comm, psb_e_get_mpi_comm + end interface psb_get_mpi_comm + + interface psb_get_mpi_rank + module procedure psb_m_get_mpi_rank, psb_e_get_mpi_rank + end interface psb_get_mpi_rank #if defined(SERIAL_MPI) integer(psb_mpk_), private, save :: nctxt=0 @@ -563,17 +570,33 @@ contains end subroutine psb_info_mpik - function psb_get_mpi_comm(ictxt) result(comm) + function psb_m_get_mpi_comm(ictxt) result(comm) integer(psb_mpk_) :: ictxt, comm comm = ictxt - end function psb_get_mpi_comm + end function psb_m_get_mpi_comm - function psb_get_mpi_rank(ictxt,id) result(rank) - integer(psb_mpk_) :: rank,ictxt,id + function psb_e_get_mpi_comm(ictxt) result(comm) + integer(psb_epk_) :: ictxt + integer(psb_mpk_) :: comm + + comm = ictxt + end function psb_e_get_mpi_comm + + function psb_m_get_mpi_rank(ictxt,id) result(rank) + integer(psb_mpk_) :: rank + integer(psb_mpk_) :: ictxt,id rank = id - end function psb_get_mpi_rank + end function psb_m_get_mpi_rank + + + function psb_e_get_mpi_rank(ictxt,id) result(rank) + integer(psb_mpk_) :: rank + integer(psb_epk_) :: ictxt,id + + rank = id + end function psb_e_get_mpi_rank subroutine psb_get_mpicomm(ictxt,comm) diff --git a/base/modules/penv/psi_s_collective_mod.F90 b/base/modules/penv/psi_s_collective_mod.F90 index 5de46599d..eda869614 100644 --- a/base/modules/penv/psi_s_collective_mod.F90 +++ b/base/modules/penv/psi_s_collective_mod.F90 @@ -31,6 +31,7 @@ ! module psi_s_collective_mod use psi_penv_mod + use psi_comm_buffers_mod interface psb_max module procedure psb_smaxs, psb_smaxv, psb_smaxm, & @@ -76,7 +77,13 @@ module psi_s_collective_mod module procedure psb_sexscan_sums, psb_sexscan_sumv end interface psb_exscan_sum + interface psb_simple_a2av + module procedure psb_s_simple_a2av + end interface psb_simple_a2av + interface psb_simple_triad_a2av + module procedure psb_s_e_simple_triad_a2av, psb_s_m_simple_triad_a2av + end interface psb_simple_triad_a2av contains @@ -1255,16 +1262,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_spk_), intent(inout) :: dat real(psb_spk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_scan(dat,dat_,1,psb_mpi_r_spk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_r_spk_,mpi_sum,icomm,minfo) dat = dat_ #endif end subroutine psb_sscan_sums @@ -1278,16 +1286,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_spk_), intent(inout) :: dat real(psb_spk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_exscan(dat,dat_,1,psb_mpi_r_spk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_r_spk_,mpi_sum,icomm,minfo) dat = dat_ #else dat = szero @@ -1303,20 +1312,21 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_spk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ real(psb_spk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_scan(dat,dat_,size(dat),psb_mpi_r_spk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_r_spk_,mpi_sum,icomm,minfo) #endif end subroutine psb_sscan_sumv @@ -1329,23 +1339,228 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt real(psb_spk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ real(psb_spk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_exscan(dat,dat_,size(dat),psb_mpi_r_spk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_r_spk_,mpi_sum,icomm,minfo) #else dat = szero #endif end subroutine psb_sexscan_sumv + + subroutine psb_s_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_s_p2p_mod + implicit none + real(psb_spk_), intent(in) :: valsnd(:) + real(psb_spk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_s_simple_a2av + + subroutine psb_s_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + real(psb_spk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + real(psb_spk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_real_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_r_spk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_real_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_spk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_s_m_simple_triad_a2av + + subroutine psb_s_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + real(psb_spk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + real(psb_spk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_real_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_r_spk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_real_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_s_e_simple_triad_a2av + end module psi_s_collective_mod diff --git a/base/modules/penv/psi_z_collective_mod.F90 b/base/modules/penv/psi_z_collective_mod.F90 index 33fe77642..a517cb031 100644 --- a/base/modules/penv/psi_z_collective_mod.F90 +++ b/base/modules/penv/psi_z_collective_mod.F90 @@ -31,6 +31,7 @@ ! module psi_z_collective_mod use psi_penv_mod + use psi_comm_buffers_mod interface psb_sum @@ -62,7 +63,13 @@ module psi_z_collective_mod module procedure psb_zexscan_sums, psb_zexscan_sumv end interface psb_exscan_sum + interface psb_simple_a2av + module procedure psb_z_simple_a2av + end interface psb_simple_a2av + interface psb_simple_triad_a2av + module procedure psb_z_e_simple_triad_a2av, psb_z_m_simple_triad_a2av + end interface psb_simple_triad_a2av contains @@ -764,16 +771,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt complex(psb_dpk_), intent(inout) :: dat complex(psb_dpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_scan(dat,dat_,1,psb_mpi_c_dpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_scan(dat,dat_,1,psb_mpi_c_dpk_,mpi_sum,icomm,minfo) dat = dat_ #endif end subroutine psb_zscan_sums @@ -787,16 +795,17 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt complex(psb_dpk_), intent(inout) :: dat complex(psb_dpk_) :: dat_ - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: icomm, minfo #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call mpi_exscan(dat,dat_,1,psb_mpi_c_dpk_,mpi_sum,ictxt,info) + icomm = psb_get_mpi_comm(ictxt) + call mpi_exscan(dat,dat_,1,psb_mpi_c_dpk_,mpi_sum,icomm,minfo) dat = dat_ #else dat = zzero @@ -812,20 +821,21 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt complex(psb_dpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ complex(psb_dpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_scan(dat,dat_,size(dat),psb_mpi_c_dpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_scan(dat,dat_,size(dat),psb_mpi_c_dpk_,mpi_sum,icomm,minfo) #endif end subroutine psb_zscan_sumv @@ -838,23 +848,228 @@ contains #ifdef MPI_H include 'mpif.h' #endif - integer(psb_mpk_), intent(in) :: ictxt + integer(psb_ipk_), intent(in) :: ictxt complex(psb_dpk_), intent(inout) :: dat(:) - integer(psb_mpk_), intent(in), optional :: root + integer(psb_ipk_), intent(in), optional :: root integer(psb_mpk_) :: root_ complex(psb_dpk_), allocatable :: dat_(:) - integer(psb_mpk_) :: iam, np, info - integer(psb_ipk_) :: iinfo + integer(psb_ipk_) :: iam, np, info + integer(psb_mpk_) :: minfo, icomm #if !defined(SERIAL_MPI) call psb_info(ictxt,iam,np) - call psb_realloc(size(dat),dat_,iinfo) + icomm = psb_get_mpi_comm(ictxt) + call psb_realloc(size(dat),dat_,info) dat_ = dat - if (iinfo == psb_success_) & - & call mpi_exscan(dat,dat_,size(dat),psb_mpi_c_dpk_,mpi_sum,ictxt,info) + if (info == psb_success_) & + & call mpi_exscan(dat,dat_,size(dat),psb_mpi_c_dpk_,mpi_sum,icomm,minfo) #else dat = zzero #endif end subroutine psb_zexscan_sumv + + subroutine psb_z_simple_a2av(valsnd,sdsz,bsdindx,& + & valrcv,rvsz,brvindx,ictxt,info) + use psi_z_p2p_mod + implicit none + complex(psb_dpk_), intent(in) :: valsnd(:) + complex(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + + call psb_info(ictxt,iam,np) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + idx = bsdindx(ip+1) + call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) + end if + end do + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + idx = brvindx(ip+1) + call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) + end if + end do + + end subroutine psb_z_simple_a2av + + subroutine psb_z_m_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + complex(psb_dpk_), intent(in) :: valsnd(:) + integer(psb_mpk_), intent(in) :: iasnd(:), jasnd(:) + complex(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_mpk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_dcomplex_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_c_dpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_dcomplex_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_c_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_mpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_z_m_simple_triad_a2av + + subroutine psb_z_e_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & valrcv,iarcv,jarcv,rvsz,brvindx,ictxt,info) +#ifdef MPI_MOD + use mpi +#endif + implicit none +#ifdef MPI_H + include 'mpif.h' +#endif + complex(psb_dpk_), intent(in) :: valsnd(:) + integer(psb_epk_), intent(in) :: iasnd(:), jasnd(:) + complex(psb_dpk_), intent(out) :: valrcv(:) + integer(psb_epk_), intent(out) :: iarcv(:), jarcv(:) + integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) + integer(psb_ipk_), intent(in) :: ictxt + integer(psb_ipk_), intent(out) :: info + + !Local variables + integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter + integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret, icomm + integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) + + call psb_info(ictxt,iam,np) + + icomm = psb_get_mpi_comm(ictxt) + + if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then + prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = brvindx(ip+1) + p2ptag = psb_dcomplex_tag + call mpi_irecv(valrcv(idx+1:idx+sz),sz,& + & psb_mpi_c_dpk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,1),iret) + p2ptag = psb_int_swap_tag + call mpi_irecv(iarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,2),iret) + call mpi_irecv(jarcv(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,rvhd(ip+1,3),iret) + end if + Enddo + + + do ip = 0, np-1 + sz = sdsz(ip+1) + if (sz > 0) then + if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) + idx = bsdindx(ip+1) + p2ptag = psb_dcomplex_tag + call mpi_send(valsnd(idx+1:idx+sz),sz,& + & psb_mpi_r_dpk_,prcid(ip+1),& + & p2ptag, icomm,iret) + p2ptag = psb_int_swap_tag + call mpi_send(iasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + call mpi_send(jasnd(idx+1:idx+sz),sz,& + & psb_mpi_epk_,prcid(ip+1),& + & p2ptag, icomm,iret) + end if + Enddo + + do ip = 0, np-1 + sz = rvsz(ip+1) + if (sz > 0) then + call mpi_wait(rvhd(ip+1,1),p2pstat,iret) + call mpi_wait(rvhd(ip+1,2),p2pstat,iret) + call mpi_wait(rvhd(ip+1,3),p2pstat,iret) + end if + Enddo + + end subroutine psb_z_e_simple_triad_a2av + end module psi_z_collective_mod diff --git a/base/modules/psb_const_mod.F90 b/base/modules/psb_const_mod.F90 index 92def010a..648a1669f 100644 --- a/base/modules/psb_const_mod.F90 +++ b/base/modules/psb_const_mod.F90 @@ -103,9 +103,9 @@ module psb_const_mod integer(psb_ipk_), save :: psb_sizeof_sp integer(psb_ipk_), save :: psb_sizeof_dp - integer(psb_ipk_), save :: psb_sizeof_i2p - integer(psb_ipk_), save :: psb_sizeof_mp = 4 - integer(psb_ipk_), save :: psb_sizeof_ep = 8 + integer(psb_ipk_), save :: psb_sizeof_i2p = 2 + integer(psb_ipk_), save :: psb_sizeof_mp = 4 + integer(psb_ipk_), save :: psb_sizeof_ep = 8 #if defined(IPK4) && defined(LPK4) integer(psb_ipk_), save :: psb_sizeof_ip = 4 @@ -145,13 +145,15 @@ module psb_const_mod ! Handy & miscellaneous constants ! integer(psb_epk_), parameter :: ezero=0, eone=1 - integer(psb_epk_), parameter :: etwo=2, ethree=3,emone=-1 + integer(psb_epk_), parameter :: etwo=2, ethree=3, emone=-1 integer(psb_mpk_), parameter :: mzero=0, mone=1 - integer(psb_mpk_), parameter :: mtwo=2, mthree=3,mmone=-1 + integer(psb_mpk_), parameter :: mtwo=2, mthree=3, mmone=-1 integer(psb_lpk_), parameter :: lzero=0, lone=1 - integer(psb_lpk_), parameter :: ltwo=2, lthree=3,lmone=-1 + integer(psb_lpk_), parameter :: ltwo=2, lthree=3, lmone=-1 integer(psb_ipk_), parameter :: izero=0, ione=1 - integer(psb_ipk_), parameter :: itwo=2, ithree=3,imone=-1 + integer(psb_ipk_), parameter :: itwo=2, ithree=3, imone=-1 + integer(psb_i2pk_), parameter :: i2zero=0, i2one=1 + integer(psb_i2pk_), parameter :: i2two=2, i2three=3, i2mone=-1 integer(psb_ipk_), parameter :: psb_root_=0 real(psb_spk_), parameter :: szero=0.0_psb_spk_, sone=1.0_psb_spk_ diff --git a/base/modules/psb_timers_mod.f90 b/base/modules/psb_timers_mod.f90 index 5b2a8054d..755afd24d 100644 --- a/base/modules/psb_timers_mod.f90 +++ b/base/modules/psb_timers_mod.f90 @@ -56,7 +56,7 @@ module psb_timers_mod ! The data itself type psb_string_item - character(len=:), allocatable :: data + character(len=40) :: data end type psb_string_item integer(psb_ipk_), allocatable :: nsamples(:) real(psb_dpk_), allocatable :: timers(:,:) diff --git a/base/modules/serial/psb_base_mat_mod.F90 b/base/modules/serial/psb_base_mat_mod.F90 index 8ebc7dc2f..9180142ac 100644 --- a/base/modules/serial/psb_base_mat_mod.F90 +++ b/base/modules/serial/psb_base_mat_mod.F90 @@ -1,9 +1,9 @@ -! +! ! Parallel Sparse BLAS version 3.5 ! (C) Copyright 2006-2018 -! Salvatore Filippone -! Alfredo Buttari -! +! 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: @@ -15,7 +15,7 @@ ! 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 @@ -27,8 +27,8 @@ ! 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. -! -! +! +! ! ! package: psb_base_mat_mod ! @@ -64,15 +64,15 @@ ! of the indices, which are PSB_LPK_ so that the entries ! are guaranteed to be able to contain global indices. ! This type only supports data handling and preprocessing, it is -! not supposed to be used for computations. +! not supposed to be used for computations. ! ! module psb_base_mat_mod - - use psb_const_mod + + use psb_const_mod use psi_serial_mod - + ! !> \namespace psb_base_mod \class psb_base_sparse_mat !! The basic data about your matrix. @@ -81,7 +81,7 @@ module psb_base_mat_mod !! storage formats. The grandchild classes are then !! encapsulated to implement the STATE design pattern. !! We have an ambiguity in that the inner class has a - !! "state" variable; we hope the context will make it clear. + !! "state" variable; we hope the context will make it clear. !! !! !! The methods associated to this class can be grouped into three sets: @@ -106,7 +106,7 @@ module psb_base_mat_mod !> Row size integer(psb_ipk_), private :: m !> Col size - integer(psb_ipk_), private :: n + integer(psb_ipk_), private :: n !> Matrix state: !! null: pristine; !! build: it's being filled with entries; @@ -114,17 +114,17 @@ module psb_base_mat_mod !! update: accepts coefficients but only !! in already existing entries. !! The transitions among the states are detailed in - !! psb_T_mat_mod. + !! psb_T_mat_mod. integer(psb_ipk_), private :: state !> How to treat duplicate elements when - !! transitioning from the BUILD to the ASSEMBLED state. + !! transitioning from the BUILD to the ASSEMBLED state. !! While many formats would allow for duplicate !! entries, it is much better to constrain the matrices !! NOT to have duplicate entries, except while in the !! BUILD state; in our overall design, only COO matrices !! can ever be in the BUILD state, hence all other formats !! cannot have duplicate entries. - integer(psb_ipk_), private :: duplicate + integer(psb_ipk_), private :: duplicate !> Is the matrix symmetric? (must also be square) logical, private :: symmetric !> Is the matrix triangular? (must also be square) @@ -137,11 +137,11 @@ module psb_base_mat_mod logical, private :: sorted logical, private :: repeatable_updates=.false. - contains + contains ! == = ================================= ! - ! Getters + ! Getters ! ! ! == = ================================= @@ -168,10 +168,10 @@ module psb_base_mat_mod procedure, pass(a) :: is_by_rows => psb_base_is_by_rows procedure, pass(a) :: is_by_cols => psb_base_is_by_cols procedure, pass(a) :: is_repeatable_updates => psb_base_is_repeatable_updates - + ! == = ================================= ! - ! Setters + ! Setters ! ! == = ================================= procedure, pass(a) :: set_nrows => psb_base_set_nrows @@ -196,7 +196,7 @@ module psb_base_mat_mod ! ! Data management ! - ! == = ================================= + ! == = ================================= procedure, pass(a) :: get_neigh => psb_base_get_neigh procedure, pass(a) :: free => psb_base_free procedure, pass(a) :: asb => psb_base_mat_asb @@ -224,7 +224,7 @@ module psb_base_mat_mod ! Any derived class having extra storage upon sync ! will guarantee that both fortran/host side and ! external side contain the same data. The base - ! version is only a placeholder. + ! version is only a placeholder. ! procedure, pass(a) :: sync => psb_base_mat_sync procedure, pass(a) :: is_host => psb_base_mat_is_host @@ -233,7 +233,7 @@ module psb_base_mat_mod procedure, pass(a) :: set_host => psb_base_mat_set_host procedure, pass(a) :: set_dev => psb_base_mat_set_dev procedure, pass(a) :: set_sync => psb_base_mat_set_sync - + end type psb_base_sparse_mat !> Function: psb_base_get_nz_row @@ -242,7 +242,7 @@ module psb_base_mat_mod !! count(A(idx,:)/=0) !! \param idx The line we are interested in. ! - interface + interface function psb_base_get_nz_row(idx,a) result(res) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat integer(psb_ipk_), intent(in) :: idx @@ -250,14 +250,14 @@ module psb_base_mat_mod integer(psb_ipk_) :: res end function psb_base_get_nz_row end interface - + ! !> Function: psb_base_get_nzeros !! \memberof psb_base_sparse_mat - !! Interface for the get_nzeros method. Equivalent to: - !! count(A(:,:)/=0) + !! Interface for the get_nzeros method. Equivalent to: + !! count(A(:,:)/=0) ! - interface + interface function psb_base_get_nzeros(a) result(res) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat class(psb_base_sparse_mat), intent(in) :: a @@ -270,9 +270,9 @@ module psb_base_mat_mod !! how many items can A hold with !! its current space allocation? !! (as opposed to how many are - !! currently occupied) - ! - interface + !! currently occupied) + ! + interface function psb_base_get_size(a) result(res) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat class(psb_base_sparse_mat), intent(in) :: a @@ -284,34 +284,34 @@ module psb_base_mat_mod !> Function reinit: transition state from ASB to UPDATE !! \memberof psb_base_sparse_mat !! \param clear [true] explicitly zero out coefficients. - ! - interface + ! + interface subroutine psb_base_reinit(a,clear) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat - class(psb_base_sparse_mat), intent(inout) :: a + class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: clear end subroutine psb_base_reinit end interface - + ! !> Function !! \memberof psb_base_sparse_mat - !! print on file in Matrix Market format. + !! print on file in Matrix Market format. !! \param iout the output unit !! \param iv(:) [none] renumber both row and column indices !! \param head [none] a descriptive header for the matrix data !! \param ivr(:) [none] renumbering for the rows !! \param ivc(:) [none] renumbering for the cols - ! - interface + ! + interface subroutine psb_base_sparse_print(iout,a,iv,head,ivr,ivc) - import :: psb_ipk_, psb_epk_, psb_base_sparse_mat + import :: psb_ipk_, psb_epk_, psb_base_sparse_mat, psb_lpk_ integer(psb_ipk_), intent(in) :: iout - class(psb_base_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + class(psb_base_sparse_mat), intent(in) :: a + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_base_sparse_print end interface @@ -325,25 +325,25 @@ module psb_base_mat_mod !! Return a list of NZ pairs !! (IA(i),JA(i)) !! each identifying the position of a nonzero in A - !! between row indices IMIN:IMAX; + !! between row indices IMIN:IMAX; !! IA,JA are reallocated as necessary. - !! \param imin the minimum row index we are interested in - !! \param imax the minimum row index we are interested in + !! \param imin the minimum row index we are interested in + !! \param imax the minimum row index we are interested in !! \param nz the number of output coefficients !! \param ia(:) the output row indices !! \param ja(:) the output col indices !! \param info return code - !! \param jmin [1] minimum col index - !! \param jmax [a\%get_ncols()] maximum col index + !! \param jmin [1] minimum col index + !! \param jmax [a\%get_ncols()] maximum col index !! \param iren(:) [none] an array to return renumbered indices (iren(ia(:)),iren(ja(:)) !! \param rscale [false] map [min(ia(:)):max(ia(:))] onto [1:max(ia(:))-min(ia(:))+1] !! \param cscale [false] map [min(ja(:)):max(ja(:))] onto [1:max(ja(:))-min(ja(:))+1] !! ( iren cannot be specified with rscale/cscale) - !! \param append [false] append to ia,ja + !! \param append [false] append to ia,ja !! \param nzin [none] if append, then first new entry should go in entry nzin+1 - ! + ! - interface + interface subroutine psb_base_csgetptn(imin,imax,a,nz,ia,ja,info,& & jmin,jmax,iren,append,nzin,rscale,cscale) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat @@ -358,7 +358,7 @@ module psb_base_mat_mod logical, intent(in), optional :: rscale,cscale end subroutine psb_base_csgetptn end interface - + ! !> Function get_neigh: !! \memberof psb_base_sparse_mat @@ -372,21 +372,21 @@ module psb_base_mat_mod !! \param n the number of indices returned !! \param info return code !! \param lev [1] find neighbours recursively for LEV levels, - !! i.e. when lev=2 find neighours of neighbours, etc. - ! - interface + !! i.e. when lev=2 find neighours of neighbours, etc. + ! + interface subroutine psb_base_get_neigh(a,idx,neigh,n,info,lev) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat - class(psb_base_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in) :: idx - integer(psb_ipk_), intent(out) :: n + class(psb_base_sparse_mat), intent(in) :: a + integer(psb_ipk_), intent(in) :: idx + integer(psb_ipk_), intent(out) :: n integer(psb_ipk_), allocatable, intent(out) :: neigh(:) integer(psb_ipk_), intent(out) :: info - integer(psb_ipk_), optional, intent(in) :: lev + integer(psb_ipk_), optional, intent(in) :: lev end subroutine psb_base_get_neigh end interface - - ! + + ! ! !> Function allocate_mnnz !! \memberof psb_base_sparse_mat @@ -396,8 +396,8 @@ module psb_base_mat_mod !! \param n number of cols !! \param nz [estimated internally] number of nonzeros to allocate for ! - interface - subroutine psb_base_allocate_mnnz(m,n,a,nz) + interface + subroutine psb_base_allocate_mnnz(m,n,a,nz) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat integer(psb_ipk_), intent(in) :: m,n class(psb_base_sparse_mat), intent(inout) :: a @@ -405,8 +405,8 @@ module psb_base_mat_mod end subroutine psb_base_allocate_mnnz end interface - - ! + + ! ! !> Function reallocate_nz !! \memberof psb_base_sparse_mat @@ -414,40 +414,40 @@ module psb_base_mat_mod !! !! \param nz number of nonzeros to allocate for ! - interface - subroutine psb_base_reallocate_nz(nz,a) + interface + subroutine psb_base_reallocate_nz(nz,a) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat integer(psb_ipk_), intent(in) :: nz class(psb_base_sparse_mat), intent(inout) :: a end subroutine psb_base_reallocate_nz end interface - ! + ! !> Function free !! \memberof psb_base_sparse_mat !! \brief destructor ! - interface - subroutine psb_base_free(a) + interface + subroutine psb_base_free(a) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat class(psb_base_sparse_mat), intent(inout) :: a end subroutine psb_base_free end interface - - ! - !> Function trim + + ! + !> Function trim !! \memberof psb_base_sparse_mat !! \brief Memory trim !! Make sure the memory allocation of the sparse matrix is as tight as - !! possible given the actual number of nonzeros it contains. + !! possible given the actual number of nonzeros it contains. ! - interface - subroutine psb_base_trim(a) + interface + subroutine psb_base_trim(a) import :: psb_ipk_, psb_epk_, psb_base_sparse_mat class(psb_base_sparse_mat), intent(inout) :: a end subroutine psb_base_trim end interface - + ! !> \namespace psb_lbase_mod \class psb_lbase_sparse_mat !! The basic data about your matrix. @@ -456,7 +456,7 @@ module psb_base_mat_mod !! storage formats. The grandchild classes are then !! encapsulated to implement the STATE design pattern. !! We have an ambiguity in that the inner class has a - !! "state" variable; we hope the context will make it clear. + !! "state" variable; we hope the context will make it clear. !! !! !! The methods associated to this class can be grouped into three sets: @@ -481,7 +481,7 @@ module psb_base_mat_mod !> Row size integer(psb_lpk_), private :: m !> Col size - integer(psb_lpk_), private :: n + integer(psb_lpk_), private :: n !> Matrix state: !! null: pristine; !! build: it's being filled with entries; @@ -489,17 +489,17 @@ module psb_base_mat_mod !! update: accepts coefficients but only !! in already existing entries. !! The transitions among the states are detailed in - !! psb_T_mat_mod. + !! psb_T_mat_mod. integer(psb_ipk_), private :: state !> How to treat duplicate elements when - !! transitioning from the BUILD to the ASSEMBLED state. + !! transitioning from the BUILD to the ASSEMBLED state. !! While many formats would allow for duplicate !! entries, it is much better to constrain the matrices !! NOT to have duplicate entries, except while in the !! BUILD state; in our overall design, only COO matrices !! can ever be in the BUILD state, hence all other formats !! cannot have duplicate entries. - integer(psb_ipk_), private :: duplicate + integer(psb_ipk_), private :: duplicate !> Is the matrix symmetric? (must also be square) logical, private :: symmetric !> Is the matrix triangular? (must also be square) @@ -512,11 +512,11 @@ module psb_base_mat_mod logical, private :: sorted logical, private :: repeatable_updates=.false. - contains + contains ! == = ================================= ! - ! Getters + ! Getters ! ! ! == = ================================= @@ -543,15 +543,15 @@ module psb_base_mat_mod procedure, pass(a) :: is_by_rows => psb_lbase_is_by_rows procedure, pass(a) :: is_by_cols => psb_lbase_is_by_cols procedure, pass(a) :: is_repeatable_updates => psb_lbase_is_repeatable_updates - + ! == = ================================= ! - ! Setters + ! Setters ! ! == = ================================= procedure, pass(a) :: set_lnrows => psb_lbase_set_lnrows procedure, pass(a) :: set_lncols => psb_lbase_set_lncols -#if defined(IPK4) && defined(LPK8) +#if defined(IPK4) && defined(LPK8) procedure, pass(a) :: set_inrows => psb_lbase_set_inrows procedure, pass(a) :: set_incols => psb_lbase_set_incols generic, public :: set_nrows => set_lnrows, set_inrows @@ -559,7 +559,7 @@ module psb_base_mat_mod #else generic, public :: set_nrows => set_lnrows generic, public :: set_ncols => set_lncols -#endif +#endif procedure, pass(a) :: set_dupl => psb_lbase_set_dupl procedure, pass(a) :: set_state => psb_lbase_set_state procedure, pass(a) :: set_null => psb_lbase_set_null @@ -580,7 +580,7 @@ module psb_base_mat_mod ! ! Data management ! - ! == = ================================= + ! == = ================================= procedure, pass(a) :: get_neigh => psb_lbase_get_neigh procedure, pass(a) :: free => psb_lbase_free procedure, pass(a) :: asb => psb_lbase_mat_asb @@ -608,7 +608,7 @@ module psb_base_mat_mod ! Any derived class having extra storage upon sync ! will guarantee that both fortran/host side and ! external side contain the same data. The base - ! version is only a placeholder. + ! version is only a placeholder. ! procedure, pass(a) :: sync => psb_lbase_mat_sync procedure, pass(a) :: is_host => psb_lbase_mat_is_host @@ -617,7 +617,7 @@ module psb_base_mat_mod procedure, pass(a) :: set_host => psb_lbase_mat_set_host procedure, pass(a) :: set_dev => psb_lbase_mat_set_dev procedure, pass(a) :: set_sync => psb_lbase_mat_set_sync - + end type psb_lbase_sparse_mat !> Function: psb_lbase_get_nz_row @@ -626,7 +626,7 @@ module psb_base_mat_mod !! count(A(idx,:)/=0) !! \param idx The line we are interested in. ! - interface + interface function psb_lbase_get_nz_row(idx,a) result(res) import :: psb_lpk_, psb_epk_, psb_lbase_sparse_mat integer(psb_lpk_), intent(in) :: idx @@ -634,14 +634,14 @@ module psb_base_mat_mod integer(psb_lpk_) :: res end function psb_lbase_get_nz_row end interface - + ! !> Function: psb_lbase_get_nzeros !! \memberof psb_lbase_sparse_mat - !! Interface for the get_nzeros method. Equivalent to: - !! count(A(:,:)/=0) + !! Interface for the get_nzeros method. Equivalent to: + !! count(A(:,:)/=0) ! - interface + interface function psb_lbase_get_nzeros(a) result(res) import :: psb_lpk_, psb_epk_, psb_lbase_sparse_mat class(psb_lbase_sparse_mat), intent(in) :: a @@ -654,9 +654,9 @@ module psb_base_mat_mod !! how many items can A hold with !! its current space allocation? !! (as opposed to how many are - !! currently occupied) - ! - interface + !! currently occupied) + ! + interface function psb_lbase_get_size(a) result(res) import :: psb_lpk_, psb_epk_, psb_lbase_sparse_mat class(psb_lbase_sparse_mat), intent(in) :: a @@ -668,31 +668,31 @@ module psb_base_mat_mod !> Function reinit: transition state from ASB to UPDATE !! \memberof psb_lbase_sparse_mat !! \param clear [true] explicitly zero out coefficients. - ! - interface + ! + interface subroutine psb_lbase_reinit(a,clear) import :: psb_ipk_, psb_epk_, psb_lbase_sparse_mat - class(psb_lbase_sparse_mat), intent(inout) :: a + class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: clear end subroutine psb_lbase_reinit end interface - + ! !> Function !! \memberof psb_lbase_sparse_mat - !! print on file in Matrix Market format. + !! print on file in Matrix Market format. !! \param iout the output unit !! \param iv(:) [none] renumber both row and column indices !! \param head [none] a descriptive header for the matrix data !! \param ivr(:) [none] renumbering for the rows !! \param ivc(:) [none] renumbering for the cols - ! - interface + ! + interface subroutine psb_lbase_sparse_print(iout,a,iv,head,ivr,ivc) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat integer(psb_ipk_), intent(in) :: iout - class(psb_lbase_sparse_mat), intent(in) :: a + class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) @@ -709,25 +709,25 @@ module psb_base_mat_mod !! Return a list of NZ pairs !! (IA(i),JA(i)) !! each identifying the position of a nonzero in A - !! between row indices IMIN:IMAX; + !! between row indices IMIN:IMAX; !! IA,JA are reallocated as necessary. - !! \param imin the minimum row index we are interested in - !! \param imax the minimum row index we are interested in + !! \param imin the minimum row index we are interested in + !! \param imax the minimum row index we are interested in !! \param nz the number of output coefficients !! \param ia(:) the output row indices !! \param ja(:) the output col indices !! \param info return code - !! \param jmin [1] minimum col index - !! \param jmax [a\%get_ncols()] maximum col index + !! \param jmin [1] minimum col index + !! \param jmax [a\%get_ncols()] maximum col index !! \param iren(:) [none] an array to return renumbered indices (iren(ia(:)),iren(ja(:)) !! \param rscale [false] map [min(ia(:)):max(ia(:))] onto [1:max(ia(:))-min(ia(:))+1] !! \param cscale [false] map [min(ja(:)):max(ja(:))] onto [1:max(ja(:))-min(ja(:))+1] !! ( iren cannot be specified with rscale/cscale) - !! \param append [false] append to ia,ja + !! \param append [false] append to ia,ja !! \param nzin [none] if append, then first new entry should go in entry nzin+1 - ! + ! - interface + interface subroutine psb_lbase_csgetptn(imin,imax,a,nz,ia,ja,info,& & jmin,jmax,iren,append,nzin,rscale,cscale) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat @@ -742,7 +742,7 @@ module psb_base_mat_mod logical, intent(in), optional :: rscale,cscale end subroutine psb_lbase_csgetptn end interface - + ! !> Function get_neigh: !! \memberof psb_lbase_sparse_mat @@ -756,21 +756,21 @@ module psb_base_mat_mod !! \param n the number of indices returned !! \param info return code !! \param lev [1] find neighbours recursively for LEV levels, - !! i.e. when lev=2 find neighours of neighbours, etc. - ! - interface + !! i.e. when lev=2 find neighours of neighbours, etc. + ! + interface subroutine psb_lbase_get_neigh(a,idx,neigh,n,info,lev) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat - class(psb_lbase_sparse_mat), intent(in) :: a - integer(psb_lpk_), intent(in) :: idx - integer(psb_lpk_), intent(out) :: n + class(psb_lbase_sparse_mat), intent(in) :: a + integer(psb_lpk_), intent(in) :: idx + integer(psb_lpk_), intent(out) :: n integer(psb_lpk_), allocatable, intent(out) :: neigh(:) integer(psb_ipk_), intent(out) :: info - integer(psb_lpk_), optional, intent(in) :: lev + integer(psb_lpk_), optional, intent(in) :: lev end subroutine psb_lbase_get_neigh end interface - - ! + + ! ! !> Function allocate_mnnz !! \memberof psb_lbase_sparse_mat @@ -780,8 +780,8 @@ module psb_base_mat_mod !! \param n number of cols !! \param nz [estimated internally] number of nonzeros to allocate for ! - interface - subroutine psb_lbase_allocate_mnnz(m,n,a,nz) + interface + subroutine psb_lbase_allocate_mnnz(m,n,a,nz) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat integer(psb_lpk_), intent(in) :: m,n class(psb_lbase_sparse_mat), intent(inout) :: a @@ -789,8 +789,8 @@ module psb_base_mat_mod end subroutine psb_lbase_allocate_mnnz end interface - - ! + + ! ! !> Function reallocate_nz !! \memberof psb_lbase_sparse_mat @@ -798,249 +798,249 @@ module psb_base_mat_mod !! !! \param nz number of nonzeros to allocate for ! - interface - subroutine psb_lbase_reallocate_nz(nz,a) + interface + subroutine psb_lbase_reallocate_nz(nz,a) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat integer(psb_lpk_), intent(in) :: nz class(psb_lbase_sparse_mat), intent(inout) :: a end subroutine psb_lbase_reallocate_nz end interface - ! + ! !> Function free !! \memberof psb_lbase_sparse_mat !! \brief destructor ! - interface - subroutine psb_lbase_free(a) + interface + subroutine psb_lbase_free(a) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat class(psb_lbase_sparse_mat), intent(inout) :: a end subroutine psb_lbase_free end interface - - ! - !> Function trim + + ! + !> Function trim !! \memberof psb_lbase_sparse_mat !! \brief Memory trim !! Make sure the memory allocation of the sparse matrix is as tight as - !! possible given the actual number of nonzeros it contains. + !! possible given the actual number of nonzeros it contains. ! - interface - subroutine psb_lbase_trim(a) + interface + subroutine psb_lbase_trim(a) import :: psb_ipk_, psb_lpk_, psb_epk_, psb_lbase_sparse_mat class(psb_lbase_sparse_mat), intent(inout) :: a end subroutine psb_lbase_trim end interface - + interface assignment(=) module procedure psb_base_from_lbase, psb_lbase_from_base end interface assignment(=) - + contains - - ! + + ! !> Function sizeof !! \memberof psb_base_sparse_mat !! \brief Memory occupation in byes ! function psb_base_sizeof(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_epk_) :: res res = 8 end function psb_base_sizeof - - ! + + ! !> Function get_fmt !! \memberof psb_base_sparse_mat !! \brief return a short descriptive name (e.g. COO CSR etc.) ! function psb_base_get_fmt() result(res) - implicit none + implicit none character(len=5) :: res res = 'NULL' end function psb_base_get_fmt - ! + ! !> Function has_update !! \memberof psb_base_sparse_mat - !! \brief Does the forma have the UPDATE functionality? + !! \brief Does the forma have the UPDATE functionality? ! function psb_base_has_update() result(res) - implicit none + implicit none logical :: res res = .true. end function psb_base_has_update - + ! - ! Standard getter functions: self-explaining. + ! Standard getter functions: self-explaining. ! function psb_base_get_dupl(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%duplicate end function psb_base_get_dupl - - + + function psb_base_get_state(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%state end function psb_base_get_state - + function psb_base_get_nrows(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%m end function psb_base_get_nrows function psb_base_get_ncols(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%n end function psb_base_get_ncols - subroutine psb_base_set_nrows(m,a) - implicit none + subroutine psb_base_set_nrows(m,a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: m a%m = m end subroutine psb_base_set_nrows - subroutine psb_base_set_ncols(n,a) - implicit none + subroutine psb_base_set_ncols(n,a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: n a%n = n end subroutine psb_base_set_ncols - - subroutine psb_base_set_state(n,a) - implicit none + + subroutine psb_base_set_state(n,a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: n a%state = n end subroutine psb_base_set_state - subroutine psb_base_set_dupl(n,a) - implicit none + subroutine psb_base_set_dupl(n,a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: n a%duplicate = n end subroutine psb_base_set_dupl - subroutine psb_base_set_null(a) - implicit none + subroutine psb_base_set_null(a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a a%state = psb_spmat_null_ end subroutine psb_base_set_null - subroutine psb_base_set_bld(a) - implicit none + subroutine psb_base_set_bld(a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a a%state = psb_spmat_bld_ end subroutine psb_base_set_bld - subroutine psb_base_set_upd(a) - implicit none + subroutine psb_base_set_upd(a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a a%state = psb_spmat_upd_ end subroutine psb_base_set_upd - subroutine psb_base_set_asb(a) - implicit none + subroutine psb_base_set_asb(a) + implicit none class(psb_base_sparse_mat), intent(inout) :: a a%state = psb_spmat_asb_ end subroutine psb_base_set_asb - subroutine psb_base_set_sorted(a,val) - implicit none + subroutine psb_base_set_sorted(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%sorted = val else a%sorted = .true. end if end subroutine psb_base_set_sorted - subroutine psb_base_set_triangle(a,val) - implicit none + subroutine psb_base_set_triangle(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%triangle = val else a%triangle = .true. end if end subroutine psb_base_set_triangle - subroutine psb_base_set_symmetric(a,val) - implicit none + subroutine psb_base_set_symmetric(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%symmetric = val else a%symmetric = .true. end if end subroutine psb_base_set_symmetric - subroutine psb_base_set_unit(a,val) - implicit none + subroutine psb_base_set_unit(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%unitd = val else a%unitd = .true. end if end subroutine psb_base_set_unit - subroutine psb_base_set_lower(a,val) - implicit none + subroutine psb_base_set_lower(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%upper = .not.val else a%upper = .false. end if end subroutine psb_base_set_lower - subroutine psb_base_set_upper(a,val) - implicit none + subroutine psb_base_set_upper(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%upper = val else a%upper = .true. end if end subroutine psb_base_set_upper - subroutine psb_base_set_repeatable_updates(a,val) - implicit none + subroutine psb_base_set_repeatable_updates(a,val) + implicit none class(psb_base_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%repeatable_updates = val else a%repeatable_updates = .true. @@ -1048,70 +1048,70 @@ contains end subroutine psb_base_set_repeatable_updates function psb_base_is_triangle(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%triangle end function psb_base_is_triangle function psb_base_is_symmetric(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%symmetric end function psb_base_is_symmetric function psb_base_is_unit(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%unitd end function psb_base_is_unit function psb_base_is_upper(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%upper .and. a%triangle end function psb_base_is_upper function psb_base_is_lower(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = (.not.a%upper) .and. a%triangle end function psb_base_is_lower function psb_base_is_null(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_null_) end function psb_base_is_null function psb_base_is_bld(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_bld_) end function psb_base_is_bld function psb_base_is_upd(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_upd_) end function psb_base_is_upd function psb_base_is_asb(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_asb_) end function psb_base_is_asb function psb_base_is_sorted(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%sorted @@ -1119,21 +1119,21 @@ contains function psb_base_is_by_rows(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = .false. end function psb_base_is_by_rows function psb_base_is_by_cols(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = .false. end function psb_base_is_by_cols function psb_base_is_repeatable_updates(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res res = a%repeatable_updates @@ -1141,27 +1141,27 @@ contains ! ! has_xt_tri: does the current type support - ! extended triangle operations? - ! + ! extended triangle operations? + ! function psb_base_has_xt_tri() result(res) - implicit none + implicit none logical :: res - - res = .false. + + res = .false. end function psb_base_has_xt_tri - + ! ! TRANSP: note sorted=.false. ! better invoke a fix() too many than ! regret it later... ! subroutine psb_base_transp_2mat(a,b) - implicit none - + implicit none + class(psb_base_sparse_mat), intent(in) :: a class(psb_base_sparse_mat), intent(out) :: b - + b%m = a%n b%n = a%m b%state = a%state @@ -1172,16 +1172,16 @@ contains b%upper = .not.a%upper b%sorted = .false. b%repeatable_updates = .false. - + end subroutine psb_base_transp_2mat subroutine psb_base_transc_2mat(a,b) - implicit none - + implicit none + class(psb_base_sparse_mat), intent(in) :: a class(psb_base_sparse_mat), intent(out) :: b - + b%m = a%n b%n = a%m b%state = a%state @@ -1196,8 +1196,8 @@ contains end subroutine psb_base_transc_2mat subroutine psb_base_transp_1mat(a) - implicit none - + implicit none + class(psb_base_sparse_mat), intent(inout) :: a integer(psb_ipk_) :: itmp @@ -1211,15 +1211,15 @@ contains a%upper = .not.a%upper a%sorted = .false. a%repeatable_updates = .false. - + end subroutine psb_base_transp_1mat subroutine psb_base_transc_1mat(a) - implicit none - + implicit none + class(psb_base_sparse_mat), intent(inout) :: a - - call a%transp() + + call a%transp() end subroutine psb_base_transc_1mat @@ -1228,89 +1228,89 @@ contains !> Function base_asb: !! \memberof psb_base_sparse_mat !! \brief Sync: base version calls sync and the set_asb. - !! + !! ! subroutine psb_base_mat_asb(a) - implicit none + implicit none class(psb_base_sparse_mat), intent(inout) :: a - + call a%sync() call a%set_asb() end subroutine psb_base_mat_asb ! ! The base version of SYNC & friends does nothing, it's just ! a placeholder. - ! + ! ! !> Function base_sync: !! \memberof psb_base_sparse_mat !! \brief Sync: base version is a no-op. - !! + !! ! subroutine psb_base_mat_sync(a) - implicit none + implicit none class(psb_base_sparse_mat), target, intent(in) :: a - + end subroutine psb_base_mat_sync ! !> Function base_set_host: !! \memberof psb_base_sparse_mat !! \brief Set_host: base version is a no-op. - !! + !! ! subroutine psb_base_mat_set_host(a) - implicit none + implicit none class(psb_base_sparse_mat), intent(inout) :: a - + end subroutine psb_base_mat_set_host ! !> Function base_set_dev: !! \memberof psb_base_sparse_mat !! \brief Set_dev: base version is a no-op. - !! + !! ! subroutine psb_base_mat_set_dev(a) - implicit none + implicit none class(psb_base_sparse_mat), intent(inout) :: a - + end subroutine psb_base_mat_set_dev ! !> Function base_set_sync: !! \memberof psb_base_sparse_mat !! \brief Set_sync: base version is a no-op. - !! + !! ! subroutine psb_base_mat_set_sync(a) - implicit none + implicit none class(psb_base_sparse_mat), intent(inout) :: a - + end subroutine psb_base_mat_set_sync ! !> Function base_is_dev: !! \memberof psb_base_sparse_mat !! \brief Is matrix on eaternal device . - !! + !! ! function psb_base_mat_is_dev(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res - + res = .false. end function psb_base_mat_is_dev - + ! !> Function base_is_host !! \memberof psb_base_sparse_mat !! \brief Is matrix on standard memory . - !! + !! ! function psb_base_mat_is_host(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res @@ -1321,10 +1321,10 @@ contains !> Function base_is_sync !! \memberof psb_base_sparse_mat !! \brief Is matrix on sync . - !! + !! ! function psb_base_mat_is_sync(a) result(res) - implicit none + implicit none class(psb_base_sparse_mat), intent(in) :: a logical :: res @@ -1332,225 +1332,225 @@ contains end function psb_base_mat_is_sync - - ! + + ! !> Function sizeof !! \memberof psb_lbase_sparse_mat !! \brief Memory occupation in byes ! function psb_lbase_sizeof(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_epk_) :: res res = 8 end function psb_lbase_sizeof - - ! + + ! !> Function get_fmt !! \memberof psb_lbase_sparse_mat !! \brief return a short descriptive name (e.g. COO CSR etc.) ! function psb_lbase_get_fmt() result(res) - implicit none + implicit none character(len=5) :: res res = 'NULL' end function psb_lbase_get_fmt - ! + ! !> Function has_update !! \memberof psb_lbase_sparse_mat - !! \brief Does the forma have the UPDATE functionality? + !! \brief Does the forma have the UPDATE functionality? ! function psb_lbase_has_update() result(res) - implicit none + implicit none logical :: res res = .true. end function psb_lbase_has_update - + ! - ! Standard getter functions: self-explaining. + ! Standard getter functions: self-explaining. ! function psb_lbase_get_dupl(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%duplicate end function psb_lbase_get_dupl - - + + function psb_lbase_get_state(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%state end function psb_lbase_get_state - + function psb_lbase_get_nrows(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_lpk_) :: res res = a%m end function psb_lbase_get_nrows function psb_lbase_get_ncols(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a integer(psb_lpk_) :: res res = a%n end function psb_lbase_get_ncols - subroutine psb_lbase_set_lnrows(m,a) - implicit none + subroutine psb_lbase_set_lnrows(m,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_lpk_), intent(in) :: m a%m = m end subroutine psb_lbase_set_lnrows - subroutine psb_lbase_set_lncols(n,a) - implicit none + subroutine psb_lbase_set_lncols(n,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_lpk_), intent(in) :: n a%n = n end subroutine psb_lbase_set_lncols -#if defined(IPK4) && defined(LPK8) - subroutine psb_lbase_set_inrows(m,a) - implicit none +#if defined(IPK4) && defined(LPK8) + subroutine psb_lbase_set_inrows(m,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: m ! This cannot overflow, since ipk_ <= lpk_ a%m = m end subroutine psb_lbase_set_inrows - subroutine psb_lbase_set_incols(n,a) - implicit none + subroutine psb_lbase_set_incols(n,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: n ! This cannot overflow, since ipk_ <= lpk_ a%n = n end subroutine psb_lbase_set_incols -#endif +#endif - subroutine psb_lbase_set_state(n,a) - implicit none + subroutine psb_lbase_set_state(n,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_lpk_), intent(in) :: n a%state = n end subroutine psb_lbase_set_state - subroutine psb_lbase_set_dupl(n,a) - implicit none + subroutine psb_lbase_set_dupl(n,a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_ipk_), intent(in) :: n a%duplicate = n end subroutine psb_lbase_set_dupl - subroutine psb_lbase_set_null(a) - implicit none + subroutine psb_lbase_set_null(a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a a%state = psb_spmat_null_ end subroutine psb_lbase_set_null - subroutine psb_lbase_set_bld(a) - implicit none + subroutine psb_lbase_set_bld(a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a a%state = psb_spmat_bld_ end subroutine psb_lbase_set_bld - subroutine psb_lbase_set_upd(a) - implicit none + subroutine psb_lbase_set_upd(a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a a%state = psb_spmat_upd_ end subroutine psb_lbase_set_upd - subroutine psb_lbase_set_asb(a) - implicit none + subroutine psb_lbase_set_asb(a) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a a%state = psb_spmat_asb_ end subroutine psb_lbase_set_asb - subroutine psb_lbase_set_sorted(a,val) - implicit none + subroutine psb_lbase_set_sorted(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%sorted = val else a%sorted = .true. end if end subroutine psb_lbase_set_sorted - subroutine psb_lbase_set_triangle(a,val) - implicit none + subroutine psb_lbase_set_triangle(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%triangle = val else a%triangle = .true. end if end subroutine psb_lbase_set_triangle - subroutine psb_lbase_set_symmetric(a,val) - implicit none + subroutine psb_lbase_set_symmetric(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%symmetric = val else a%symmetric = .true. end if end subroutine psb_lbase_set_symmetric - subroutine psb_lbase_set_unit(a,val) - implicit none + subroutine psb_lbase_set_unit(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%unitd = val else a%unitd = .true. end if end subroutine psb_lbase_set_unit - subroutine psb_lbase_set_lower(a,val) - implicit none + subroutine psb_lbase_set_lower(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%upper = .not.val else a%upper = .false. end if end subroutine psb_lbase_set_lower - subroutine psb_lbase_set_upper(a,val) - implicit none + subroutine psb_lbase_set_upper(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%upper = val else a%upper = .true. end if end subroutine psb_lbase_set_upper - subroutine psb_lbase_set_repeatable_updates(a,val) - implicit none + subroutine psb_lbase_set_repeatable_updates(a,val) + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a logical, intent(in), optional :: val - - if (present(val)) then + + if (present(val)) then a%repeatable_updates = val else a%repeatable_updates = .true. @@ -1559,80 +1559,80 @@ contains ! ! has_xt_tri: does the current type support - ! extended triangle operations? - ! + ! extended triangle operations? + ! function psb_lbase_has_xt_tri() result(res) - implicit none + implicit none logical :: res - - res = .false. + + res = .false. end function psb_lbase_has_xt_tri function psb_lbase_is_triangle(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%triangle end function psb_lbase_is_triangle function psb_lbase_is_symmetric(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%symmetric end function psb_lbase_is_symmetric function psb_lbase_is_unit(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%unitd end function psb_lbase_is_unit function psb_lbase_is_upper(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%upper .and. a%triangle end function psb_lbase_is_upper function psb_lbase_is_lower(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = (.not.a%upper) .and. a%triangle end function psb_lbase_is_lower function psb_lbase_is_null(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_null_) end function psb_lbase_is_null function psb_lbase_is_bld(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_bld_) end function psb_lbase_is_bld function psb_lbase_is_upd(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_upd_) end function psb_lbase_is_upd function psb_lbase_is_asb(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = (a%state == psb_spmat_asb_) end function psb_lbase_is_asb function psb_lbase_is_sorted(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%sorted @@ -1640,38 +1640,38 @@ contains function psb_lbase_is_by_rows(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = .false. end function psb_lbase_is_by_rows function psb_lbase_is_by_cols(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = .false. end function psb_lbase_is_by_cols function psb_lbase_is_repeatable_updates(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res res = a%repeatable_updates end function psb_lbase_is_repeatable_updates - + ! ! TRANSP: note sorted=.false. ! better invoke a fix() too many than ! regret it later... ! subroutine psb_lbase_transp_2mat(a,b) - implicit none - + implicit none + class(psb_lbase_sparse_mat), intent(in) :: a class(psb_lbase_sparse_mat), intent(out) :: b - + b%m = a%n b%n = a%m b%state = a%state @@ -1681,16 +1681,16 @@ contains b%upper = .not.a%upper b%sorted = .false. b%repeatable_updates = .false. - + end subroutine psb_lbase_transp_2mat subroutine psb_lbase_transc_2mat(a,b) - implicit none - + implicit none + class(psb_lbase_sparse_mat), intent(in) :: a class(psb_lbase_sparse_mat), intent(out) :: b - + b%m = a%n b%n = a%m b%state = a%state @@ -1704,8 +1704,8 @@ contains end subroutine psb_lbase_transc_2mat subroutine psb_lbase_transp_1mat(a) - implicit none - + implicit none + class(psb_lbase_sparse_mat), intent(inout) :: a integer(psb_lpk_) :: itmp @@ -1719,15 +1719,15 @@ contains a%upper = .not.a%upper a%sorted = .false. a%repeatable_updates = .false. - + end subroutine psb_lbase_transp_1mat subroutine psb_lbase_transc_1mat(a) - implicit none - + implicit none + class(psb_lbase_sparse_mat), intent(inout) :: a - - call a%transp() + + call a%transp() end subroutine psb_lbase_transc_1mat @@ -1736,89 +1736,89 @@ contains !> Function base_asb: !! \memberof psb_lbase_sparse_mat !! \brief Sync: base version calls sync and the set_asb. - !! + !! ! subroutine psb_lbase_mat_asb(a) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a - + call a%sync() call a%set_asb() end subroutine psb_lbase_mat_asb ! ! The base version of SYNC & friends does nothing, it's just ! a placeholder. - ! + ! ! !> Function base_sync: !! \memberof psb_lbase_sparse_mat !! \brief Sync: base version is a no-op. - !! + !! ! subroutine psb_lbase_mat_sync(a) - implicit none + implicit none class(psb_lbase_sparse_mat), target, intent(in) :: a - + end subroutine psb_lbase_mat_sync ! !> Function base_set_host: !! \memberof psb_lbase_sparse_mat !! \brief Set_host: base version is a no-op. - !! + !! ! subroutine psb_lbase_mat_set_host(a) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a - + end subroutine psb_lbase_mat_set_host ! !> Function base_set_dev: !! \memberof psb_lbase_sparse_mat !! \brief Set_dev: base version is a no-op. - !! + !! ! subroutine psb_lbase_mat_set_dev(a) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a - + end subroutine psb_lbase_mat_set_dev ! !> Function base_set_sync: !! \memberof psb_lbase_sparse_mat !! \brief Set_sync: base version is a no-op. - !! + !! ! subroutine psb_lbase_mat_set_sync(a) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(inout) :: a - + end subroutine psb_lbase_mat_set_sync ! !> Function base_is_dev: !! \memberof psb_lbase_sparse_mat !! \brief Is matrix on eaternal device . - !! + !! ! function psb_lbase_mat_is_dev(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res - + res = .false. end function psb_lbase_mat_is_dev - + ! !> Function base_is_host !! \memberof psb_lbase_sparse_mat !! \brief Is matrix on standard memory . - !! + !! ! function psb_lbase_mat_is_host(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res @@ -1829,10 +1829,10 @@ contains !> Function base_is_sync !! \memberof psb_lbase_sparse_mat !! \brief Is matrix on sync . - !! + !! ! function psb_lbase_mat_is_sync(a) result(res) - implicit none + implicit none class(psb_lbase_sparse_mat), intent(in) :: a logical :: res @@ -1844,33 +1844,32 @@ contains type(psb_lbase_sparse_mat), intent(inout) :: lb type(psb_base_sparse_mat), intent(in) :: ib - lb%m = ib%m - lb%n = ib%n - lb%state = ib%state - lb%duplicate = ib%duplicate - lb%triangle = ib%triangle - lb%unitd = ib%unitd - lb%upper = ib%upper - lb%sorted = ib%sorted - lb%repeatable_updates = ib%repeatable_updates - + lb%m = ib%m + lb%n = ib%n + lb%state = ib%state + lb%duplicate = ib%duplicate + lb%triangle = ib%triangle + lb%unitd = ib%unitd + lb%upper = ib%upper + lb%sorted = ib%sorted + lb%repeatable_updates = ib%repeatable_updates + end subroutine psb_lbase_from_base subroutine psb_base_from_lbase(ib,lb) type(psb_base_sparse_mat), intent(inout) :: ib type(psb_lbase_sparse_mat), intent(in) :: lb - - ib%m = lb%m - ib%n = lb%n - ib%state = lb%state - ib%duplicate = lb%duplicate - ib%triangle = lb%triangle - ib%unitd = lb%unitd - ib%upper = lb%upper - ib%sorted = lb%sorted - ib%repeatable_updates = lb%repeatable_updates - + + ib%m = lb%m + ib%n = lb%n + ib%state = lb%state + ib%duplicate = lb%duplicate + ib%triangle = lb%triangle + ib%unitd = lb%unitd + ib%upper = lb%upper + ib%sorted = lb%sorted + ib%repeatable_updates = lb%repeatable_updates + end subroutine psb_base_from_lbase end module psb_base_mat_mod - diff --git a/base/modules/serial/psb_c_base_mat_mod.F90 b/base/modules/serial/psb_c_base_mat_mod.F90 index a52f7a7ce..6924d8198 100644 --- a/base/modules/serial/psb_c_base_mat_mod.F90 +++ b/base/modules/serial/psb_c_base_mat_mod.F90 @@ -167,6 +167,7 @@ module psb_c_base_mat_mod procedure, pass(a) :: sizeof => c_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_c_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_c_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_c_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_c_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_c_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_c_cp_coo_to_fmt @@ -191,6 +192,7 @@ module psb_c_base_mat_mod procedure, pass(a) :: fix => psb_c_fix_coo procedure, pass(a) :: trim => psb_c_coo_trim procedure, pass(a) :: clean_zeros => psb_c_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_c_coo_clean_negidx procedure, pass(a) :: print => psb_c_coo_print procedure, pass(a) :: free => c_coo_free procedure, pass(a) :: mold => psb_c_coo_mold @@ -360,6 +362,7 @@ module psb_c_base_mat_mod procedure, pass(a) :: sizeof => lc_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_lc_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_lc_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_lc_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_lc_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_lc_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_lc_cp_coo_to_fmt @@ -380,6 +383,7 @@ module psb_c_base_mat_mod procedure, pass(a) :: fix => psb_lc_fix_coo procedure, pass(a) :: trim => psb_lc_coo_trim procedure, pass(a) :: clean_zeros => psb_lc_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_lc_coo_clean_negidx procedure, pass(a) :: print => psb_lc_coo_print procedure, pass(a) :: free => lc_coo_free procedure, pass(a) :: mold => psb_lc_coo_mold @@ -1678,6 +1682,17 @@ module psb_c_base_mat_mod class(psb_c_coo_sparse_mat), intent(inout) :: a end subroutine psb_c_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_c_coo_sparse_mat + ! + interface + subroutine psb_c_coo_ensure_size(nz,a) + import + integer(psb_ipk_), intent(in) :: nz + class(psb_c_coo_sparse_mat), intent(inout) :: a + end subroutine psb_c_coo_ensure_size + end interface ! !> @@ -1715,6 +1730,46 @@ module psb_c_base_mat_mod end subroutine psb_c_coo_clean_zeros end interface + ! + !> + !! \memberof psb_c_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_c_coo_clean_negidx(a,info) + import + class(psb_c_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_c_coo_clean_negidx + end interface + + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_c_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + complex(psb_spk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_c_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner + + ! !> !! \memberof psb_c_coo_sparse_mat @@ -1759,9 +1814,9 @@ module psb_c_base_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_c_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_c_coo_print end interface @@ -3279,6 +3334,17 @@ module psb_c_base_mat_mod class(psb_lc_coo_sparse_mat), intent(inout) :: a end subroutine psb_lc_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_lc_coo_sparse_mat + ! + interface + subroutine psb_lc_coo_ensure_size(nz,a) + import + integer(psb_lpk_), intent(in) :: nz + class(psb_lc_coo_sparse_mat), intent(inout) :: a + end subroutine psb_lc_coo_ensure_size + end interface ! !> @@ -3316,6 +3382,46 @@ module psb_c_base_mat_mod end subroutine psb_lc_coo_clean_zeros end interface + ! + !> + !! \memberof psb_lc_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_lc_coo_clean_negidx(a,info) + import + class(psb_lc_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lc_coo_clean_negidx + end interface + +#if defined(IPK4) && defined(LPK8) + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_lc_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + complex(psb_spk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lc_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner +#endif ! !> !! \memberof psb_lc_coo_sparse_mat @@ -3674,6 +3780,8 @@ module psb_c_base_mat_mod end subroutine psb_lc_coo_scals end interface + public :: psb_c_get_print_frmt, psb_lc_get_print_frmt + !> !! \memberof psb_lc_coo_sparse_mat !! \see psb_lc_base_mat_mod::psb_lc_base_scalplusidentity @@ -3729,6 +3837,56 @@ module psb_c_base_mat_mod contains + function psb_c_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_ipk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='complex' + integer(psb_lpk_) :: nmx + integer(psb_ipk_) :: ni + nmx = max(nr,nc,ione) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_c_get_print_frmt + + function psb_lc_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_lpk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='complex' + integer(psb_lpk_) :: nmx + integer(psb_lpk_) :: ni + nmx = max(nr,nc,lone) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_lc_get_print_frmt + ! == ================================== ! diff --git a/base/modules/serial/psb_c_csc_mat_mod.f90 b/base/modules/serial/psb_c_csc_mat_mod.f90 index ad59f0f19..bb06977b8 100644 --- a/base/modules/serial/psb_c_csc_mat_mod.f90 +++ b/base/modules/serial/psb_c_csc_mat_mod.f90 @@ -219,9 +219,9 @@ module psb_c_csc_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_c_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_c_csc_print end interface diff --git a/base/modules/serial/psb_c_csr_mat_mod.f90 b/base/modules/serial/psb_c_csr_mat_mod.f90 index e9004b3c0..8b076cc22 100644 --- a/base/modules/serial/psb_c_csr_mat_mod.f90 +++ b/base/modules/serial/psb_c_csr_mat_mod.f90 @@ -169,9 +169,9 @@ module psb_c_csr_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_c_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_c_csr_print end interface ! diff --git a/base/modules/serial/psb_c_mat_mod.F90 b/base/modules/serial/psb_c_mat_mod.F90 index 82d565ec8..a7c7e3583 100644 --- a/base/modules/serial/psb_c_mat_mod.F90 +++ b/base/modules/serial/psb_c_mat_mod.F90 @@ -145,8 +145,9 @@ module psb_c_mat_mod procedure, pass(a) :: tril => psb_c_tril procedure, pass(a) :: triu => psb_c_triu procedure, pass(a) :: m_csclip => psb_c_csclip + procedure, pass(a) :: m_csclip_ip => psb_c_csclip_ip procedure, pass(a) :: b_csclip => psb_c_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_c_clean_zeros procedure, pass(a) :: reall => psb_c_reallocate_nz procedure, pass(a) :: get_neigh => psb_c_get_neigh @@ -342,8 +343,9 @@ module psb_c_mat_mod procedure, pass(a) :: tril => psb_lc_tril procedure, pass(a) :: triu => psb_lc_triu procedure, pass(a) :: m_csclip => psb_lc_csclip + procedure, pass(a) :: m_csclip_ip => psb_lc_csclip_ip procedure, pass(a) :: b_csclip => psb_lc_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_lc_clean_zeros procedure, pass(a) :: reall => psb_lc_reallocate_nz procedure, pass(a) :: get_neigh => psb_lc_get_neigh @@ -573,9 +575,9 @@ module psb_c_mat_mod import :: psb_ipk_, psb_lpk_, psb_cspmat_type integer(psb_ipk_), intent(in) :: iout class(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_c_sparse_print end interface @@ -584,9 +586,9 @@ module psb_c_mat_mod import :: psb_ipk_, psb_lpk_, psb_cspmat_type character(len=*), intent(in) :: fname class(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_c_n_sparse_print end interface @@ -745,6 +747,17 @@ module psb_c_mat_mod end subroutine psb_c_csclip end interface + interface + subroutine psb_c_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_cspmat_type, psb_spk_ + class(psb_cspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_c_csclip_ip + end interface + interface subroutine psb_c_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -1514,6 +1527,17 @@ module psb_c_mat_mod end subroutine psb_lc_csclip end interface + interface + subroutine psb_lc_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_lcspmat_type, psb_spk_ + class(psb_lcspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_lc_csclip_ip + end interface + interface subroutine psb_lc_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) diff --git a/base/modules/serial/psb_c_serial_mod.f90 b/base/modules/serial/psb_c_serial_mod.f90 index b3e3abd09..9c43f3e76 100644 --- a/base/modules/serial/psb_c_serial_mod.f90 +++ b/base/modules/serial/psb_c_serial_mod.f90 @@ -292,9 +292,9 @@ contains use psb_c_mat_mod, only : psb_cspmat_type integer(psb_ipk_), intent(in) :: iout type(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(iout,iv,head,ivr,ivc) @@ -304,9 +304,9 @@ contains use psb_c_mat_mod, only : psb_cspmat_type character(len=*), intent(in) :: fname type(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(fname,iv,head,ivr,ivc) diff --git a/base/modules/serial/psb_d_base_mat_mod.F90 b/base/modules/serial/psb_d_base_mat_mod.F90 index a4b78e82f..a6ff7c5ec 100644 --- a/base/modules/serial/psb_d_base_mat_mod.F90 +++ b/base/modules/serial/psb_d_base_mat_mod.F90 @@ -167,6 +167,7 @@ module psb_d_base_mat_mod procedure, pass(a) :: sizeof => d_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_d_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_d_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_d_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_d_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_d_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_d_cp_coo_to_fmt @@ -191,6 +192,7 @@ module psb_d_base_mat_mod procedure, pass(a) :: fix => psb_d_fix_coo procedure, pass(a) :: trim => psb_d_coo_trim procedure, pass(a) :: clean_zeros => psb_d_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_d_coo_clean_negidx procedure, pass(a) :: print => psb_d_coo_print procedure, pass(a) :: free => d_coo_free procedure, pass(a) :: mold => psb_d_coo_mold @@ -360,6 +362,7 @@ module psb_d_base_mat_mod procedure, pass(a) :: sizeof => ld_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_ld_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_ld_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_ld_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_ld_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_ld_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_ld_cp_coo_to_fmt @@ -380,6 +383,7 @@ module psb_d_base_mat_mod procedure, pass(a) :: fix => psb_ld_fix_coo procedure, pass(a) :: trim => psb_ld_coo_trim procedure, pass(a) :: clean_zeros => psb_ld_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_ld_coo_clean_negidx procedure, pass(a) :: print => psb_ld_coo_print procedure, pass(a) :: free => ld_coo_free procedure, pass(a) :: mold => psb_ld_coo_mold @@ -1678,6 +1682,17 @@ module psb_d_base_mat_mod class(psb_d_coo_sparse_mat), intent(inout) :: a end subroutine psb_d_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_d_coo_sparse_mat + ! + interface + subroutine psb_d_coo_ensure_size(nz,a) + import + integer(psb_ipk_), intent(in) :: nz + class(psb_d_coo_sparse_mat), intent(inout) :: a + end subroutine psb_d_coo_ensure_size + end interface ! !> @@ -1715,6 +1730,46 @@ module psb_d_base_mat_mod end subroutine psb_d_coo_clean_zeros end interface + ! + !> + !! \memberof psb_d_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_d_coo_clean_negidx(a,info) + import + class(psb_d_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_d_coo_clean_negidx + end interface + + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_d_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + real(psb_dpk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_d_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner + + ! !> !! \memberof psb_d_coo_sparse_mat @@ -1759,9 +1814,9 @@ module psb_d_base_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_d_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_d_coo_print end interface @@ -3279,6 +3334,17 @@ module psb_d_base_mat_mod class(psb_ld_coo_sparse_mat), intent(inout) :: a end subroutine psb_ld_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_ld_coo_sparse_mat + ! + interface + subroutine psb_ld_coo_ensure_size(nz,a) + import + integer(psb_lpk_), intent(in) :: nz + class(psb_ld_coo_sparse_mat), intent(inout) :: a + end subroutine psb_ld_coo_ensure_size + end interface ! !> @@ -3316,6 +3382,46 @@ module psb_d_base_mat_mod end subroutine psb_ld_coo_clean_zeros end interface + ! + !> + !! \memberof psb_ld_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_ld_coo_clean_negidx(a,info) + import + class(psb_ld_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ld_coo_clean_negidx + end interface + +#if defined(IPK4) && defined(LPK8) + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_ld_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + real(psb_dpk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ld_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner +#endif ! !> !! \memberof psb_ld_coo_sparse_mat @@ -3674,6 +3780,8 @@ module psb_d_base_mat_mod end subroutine psb_ld_coo_scals end interface + public :: psb_d_get_print_frmt, psb_ld_get_print_frmt + !> !! \memberof psb_ld_coo_sparse_mat !! \see psb_ld_base_mat_mod::psb_ld_base_scalplusidentity @@ -3729,6 +3837,56 @@ module psb_d_base_mat_mod contains + function psb_d_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_ipk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='real' + integer(psb_lpk_) :: nmx + integer(psb_ipk_) :: ni + nmx = max(nr,nc,ione) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_d_get_print_frmt + + function psb_ld_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_lpk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='real' + integer(psb_lpk_) :: nmx + integer(psb_lpk_) :: ni + nmx = max(nr,nc,lone) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_ld_get_print_frmt + ! == ================================== ! diff --git a/base/modules/serial/psb_d_csc_mat_mod.f90 b/base/modules/serial/psb_d_csc_mat_mod.f90 index 42cefb723..60d91bf29 100644 --- a/base/modules/serial/psb_d_csc_mat_mod.f90 +++ b/base/modules/serial/psb_d_csc_mat_mod.f90 @@ -219,9 +219,9 @@ module psb_d_csc_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_d_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_d_csc_print end interface diff --git a/base/modules/serial/psb_d_csr_mat_mod.f90 b/base/modules/serial/psb_d_csr_mat_mod.f90 index e6f926e83..d0aa622bb 100644 --- a/base/modules/serial/psb_d_csr_mat_mod.f90 +++ b/base/modules/serial/psb_d_csr_mat_mod.f90 @@ -169,9 +169,9 @@ module psb_d_csr_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_d_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_d_csr_print end interface ! diff --git a/base/modules/serial/psb_d_mat_mod.F90 b/base/modules/serial/psb_d_mat_mod.F90 index 263192399..354c4199e 100644 --- a/base/modules/serial/psb_d_mat_mod.F90 +++ b/base/modules/serial/psb_d_mat_mod.F90 @@ -145,8 +145,9 @@ module psb_d_mat_mod procedure, pass(a) :: tril => psb_d_tril procedure, pass(a) :: triu => psb_d_triu procedure, pass(a) :: m_csclip => psb_d_csclip + procedure, pass(a) :: m_csclip_ip => psb_d_csclip_ip procedure, pass(a) :: b_csclip => psb_d_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_d_clean_zeros procedure, pass(a) :: reall => psb_d_reallocate_nz procedure, pass(a) :: get_neigh => psb_d_get_neigh @@ -342,8 +343,9 @@ module psb_d_mat_mod procedure, pass(a) :: tril => psb_ld_tril procedure, pass(a) :: triu => psb_ld_triu procedure, pass(a) :: m_csclip => psb_ld_csclip + procedure, pass(a) :: m_csclip_ip => psb_ld_csclip_ip procedure, pass(a) :: b_csclip => psb_ld_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_ld_clean_zeros procedure, pass(a) :: reall => psb_ld_reallocate_nz procedure, pass(a) :: get_neigh => psb_ld_get_neigh @@ -573,9 +575,9 @@ module psb_d_mat_mod import :: psb_ipk_, psb_lpk_, psb_dspmat_type integer(psb_ipk_), intent(in) :: iout class(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_d_sparse_print end interface @@ -584,9 +586,9 @@ module psb_d_mat_mod import :: psb_ipk_, psb_lpk_, psb_dspmat_type character(len=*), intent(in) :: fname class(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_d_n_sparse_print end interface @@ -745,6 +747,17 @@ module psb_d_mat_mod end subroutine psb_d_csclip end interface + interface + subroutine psb_d_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_dspmat_type, psb_dpk_ + class(psb_dspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_d_csclip_ip + end interface + interface subroutine psb_d_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -1514,6 +1527,17 @@ module psb_d_mat_mod end subroutine psb_ld_csclip end interface + interface + subroutine psb_ld_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_ldspmat_type, psb_dpk_ + class(psb_ldspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_ld_csclip_ip + end interface + interface subroutine psb_ld_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) diff --git a/base/modules/serial/psb_d_serial_mod.f90 b/base/modules/serial/psb_d_serial_mod.f90 index e43be2acd..523282f5c 100644 --- a/base/modules/serial/psb_d_serial_mod.f90 +++ b/base/modules/serial/psb_d_serial_mod.f90 @@ -292,9 +292,9 @@ contains use psb_d_mat_mod, only : psb_dspmat_type integer(psb_ipk_), intent(in) :: iout type(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(iout,iv,head,ivr,ivc) @@ -304,9 +304,9 @@ contains use psb_d_mat_mod, only : psb_dspmat_type character(len=*), intent(in) :: fname type(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(fname,iv,head,ivr,ivc) diff --git a/base/modules/serial/psb_s_base_mat_mod.F90 b/base/modules/serial/psb_s_base_mat_mod.F90 index 9069d48e0..95bab09ee 100644 --- a/base/modules/serial/psb_s_base_mat_mod.F90 +++ b/base/modules/serial/psb_s_base_mat_mod.F90 @@ -167,6 +167,7 @@ module psb_s_base_mat_mod procedure, pass(a) :: sizeof => s_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_s_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_s_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_s_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_s_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_s_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_s_cp_coo_to_fmt @@ -191,6 +192,7 @@ module psb_s_base_mat_mod procedure, pass(a) :: fix => psb_s_fix_coo procedure, pass(a) :: trim => psb_s_coo_trim procedure, pass(a) :: clean_zeros => psb_s_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_s_coo_clean_negidx procedure, pass(a) :: print => psb_s_coo_print procedure, pass(a) :: free => s_coo_free procedure, pass(a) :: mold => psb_s_coo_mold @@ -360,6 +362,7 @@ module psb_s_base_mat_mod procedure, pass(a) :: sizeof => ls_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_ls_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_ls_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_ls_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_ls_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_ls_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_ls_cp_coo_to_fmt @@ -380,6 +383,7 @@ module psb_s_base_mat_mod procedure, pass(a) :: fix => psb_ls_fix_coo procedure, pass(a) :: trim => psb_ls_coo_trim procedure, pass(a) :: clean_zeros => psb_ls_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_ls_coo_clean_negidx procedure, pass(a) :: print => psb_ls_coo_print procedure, pass(a) :: free => ls_coo_free procedure, pass(a) :: mold => psb_ls_coo_mold @@ -1678,6 +1682,17 @@ module psb_s_base_mat_mod class(psb_s_coo_sparse_mat), intent(inout) :: a end subroutine psb_s_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_s_coo_sparse_mat + ! + interface + subroutine psb_s_coo_ensure_size(nz,a) + import + integer(psb_ipk_), intent(in) :: nz + class(psb_s_coo_sparse_mat), intent(inout) :: a + end subroutine psb_s_coo_ensure_size + end interface ! !> @@ -1715,6 +1730,46 @@ module psb_s_base_mat_mod end subroutine psb_s_coo_clean_zeros end interface + ! + !> + !! \memberof psb_s_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_s_coo_clean_negidx(a,info) + import + class(psb_s_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_s_coo_clean_negidx + end interface + + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_s_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + real(psb_spk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_s_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner + + ! !> !! \memberof psb_s_coo_sparse_mat @@ -1759,9 +1814,9 @@ module psb_s_base_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_s_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_s_coo_print end interface @@ -3279,6 +3334,17 @@ module psb_s_base_mat_mod class(psb_ls_coo_sparse_mat), intent(inout) :: a end subroutine psb_ls_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_ls_coo_sparse_mat + ! + interface + subroutine psb_ls_coo_ensure_size(nz,a) + import + integer(psb_lpk_), intent(in) :: nz + class(psb_ls_coo_sparse_mat), intent(inout) :: a + end subroutine psb_ls_coo_ensure_size + end interface ! !> @@ -3316,6 +3382,46 @@ module psb_s_base_mat_mod end subroutine psb_ls_coo_clean_zeros end interface + ! + !> + !! \memberof psb_ls_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_ls_coo_clean_negidx(a,info) + import + class(psb_ls_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ls_coo_clean_negidx + end interface + +#if defined(IPK4) && defined(LPK8) + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_ls_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + real(psb_spk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ls_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner +#endif ! !> !! \memberof psb_ls_coo_sparse_mat @@ -3674,6 +3780,8 @@ module psb_s_base_mat_mod end subroutine psb_ls_coo_scals end interface + public :: psb_s_get_print_frmt, psb_ls_get_print_frmt + !> !! \memberof psb_ls_coo_sparse_mat !! \see psb_ls_base_mat_mod::psb_ls_base_scalplusidentity @@ -3729,6 +3837,56 @@ module psb_s_base_mat_mod contains + function psb_s_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_ipk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='real' + integer(psb_lpk_) :: nmx + integer(psb_ipk_) :: ni + nmx = max(nr,nc,ione) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_s_get_print_frmt + + function psb_ls_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_lpk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='real' + integer(psb_lpk_) :: nmx + integer(psb_lpk_) :: ni + nmx = max(nr,nc,lone) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_ls_get_print_frmt + ! == ================================== ! diff --git a/base/modules/serial/psb_s_csc_mat_mod.f90 b/base/modules/serial/psb_s_csc_mat_mod.f90 index 822659d94..ccd4f4457 100644 --- a/base/modules/serial/psb_s_csc_mat_mod.f90 +++ b/base/modules/serial/psb_s_csc_mat_mod.f90 @@ -219,9 +219,9 @@ module psb_s_csc_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_s_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_s_csc_print end interface diff --git a/base/modules/serial/psb_s_csr_mat_mod.f90 b/base/modules/serial/psb_s_csr_mat_mod.f90 index 01d36829a..6b4c51c79 100644 --- a/base/modules/serial/psb_s_csr_mat_mod.f90 +++ b/base/modules/serial/psb_s_csr_mat_mod.f90 @@ -169,9 +169,9 @@ module psb_s_csr_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_s_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_s_csr_print end interface ! diff --git a/base/modules/serial/psb_s_mat_mod.F90 b/base/modules/serial/psb_s_mat_mod.F90 index 32a2f378e..ee6671d38 100644 --- a/base/modules/serial/psb_s_mat_mod.F90 +++ b/base/modules/serial/psb_s_mat_mod.F90 @@ -145,8 +145,9 @@ module psb_s_mat_mod procedure, pass(a) :: tril => psb_s_tril procedure, pass(a) :: triu => psb_s_triu procedure, pass(a) :: m_csclip => psb_s_csclip + procedure, pass(a) :: m_csclip_ip => psb_s_csclip_ip procedure, pass(a) :: b_csclip => psb_s_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_s_clean_zeros procedure, pass(a) :: reall => psb_s_reallocate_nz procedure, pass(a) :: get_neigh => psb_s_get_neigh @@ -342,8 +343,9 @@ module psb_s_mat_mod procedure, pass(a) :: tril => psb_ls_tril procedure, pass(a) :: triu => psb_ls_triu procedure, pass(a) :: m_csclip => psb_ls_csclip + procedure, pass(a) :: m_csclip_ip => psb_ls_csclip_ip procedure, pass(a) :: b_csclip => psb_ls_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_ls_clean_zeros procedure, pass(a) :: reall => psb_ls_reallocate_nz procedure, pass(a) :: get_neigh => psb_ls_get_neigh @@ -573,9 +575,9 @@ module psb_s_mat_mod import :: psb_ipk_, psb_lpk_, psb_sspmat_type integer(psb_ipk_), intent(in) :: iout class(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_s_sparse_print end interface @@ -584,9 +586,9 @@ module psb_s_mat_mod import :: psb_ipk_, psb_lpk_, psb_sspmat_type character(len=*), intent(in) :: fname class(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_s_n_sparse_print end interface @@ -745,6 +747,17 @@ module psb_s_mat_mod end subroutine psb_s_csclip end interface + interface + subroutine psb_s_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_sspmat_type, psb_spk_ + class(psb_sspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_s_csclip_ip + end interface + interface subroutine psb_s_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -1514,6 +1527,17 @@ module psb_s_mat_mod end subroutine psb_ls_csclip end interface + interface + subroutine psb_ls_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_lsspmat_type, psb_spk_ + class(psb_lsspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_ls_csclip_ip + end interface + interface subroutine psb_ls_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) diff --git a/base/modules/serial/psb_s_serial_mod.f90 b/base/modules/serial/psb_s_serial_mod.f90 index 45ed7dbbe..81583f64e 100644 --- a/base/modules/serial/psb_s_serial_mod.f90 +++ b/base/modules/serial/psb_s_serial_mod.f90 @@ -292,9 +292,9 @@ contains use psb_s_mat_mod, only : psb_sspmat_type integer(psb_ipk_), intent(in) :: iout type(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(iout,iv,head,ivr,ivc) @@ -304,9 +304,9 @@ contains use psb_s_mat_mod, only : psb_sspmat_type character(len=*), intent(in) :: fname type(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(fname,iv,head,ivr,ivc) diff --git a/base/modules/serial/psb_z_base_mat_mod.F90 b/base/modules/serial/psb_z_base_mat_mod.F90 index cc7b2e22c..88ba36ec3 100644 --- a/base/modules/serial/psb_z_base_mat_mod.F90 +++ b/base/modules/serial/psb_z_base_mat_mod.F90 @@ -167,6 +167,7 @@ module psb_z_base_mat_mod procedure, pass(a) :: sizeof => z_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_z_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_z_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_z_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_z_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_z_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_z_cp_coo_to_fmt @@ -191,6 +192,7 @@ module psb_z_base_mat_mod procedure, pass(a) :: fix => psb_z_fix_coo procedure, pass(a) :: trim => psb_z_coo_trim procedure, pass(a) :: clean_zeros => psb_z_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_z_coo_clean_negidx procedure, pass(a) :: print => psb_z_coo_print procedure, pass(a) :: free => z_coo_free procedure, pass(a) :: mold => psb_z_coo_mold @@ -360,6 +362,7 @@ module psb_z_base_mat_mod procedure, pass(a) :: sizeof => lz_coo_sizeof procedure, pass(a) :: reallocate_nz => psb_lz_coo_reallocate_nz procedure, pass(a) :: allocate_mnnz => psb_lz_coo_allocate_mnnz + procedure, pass(a) :: ensure_size => psb_lz_coo_ensure_size procedure, pass(a) :: cp_to_coo => psb_lz_cp_coo_to_coo procedure, pass(a) :: cp_from_coo => psb_lz_cp_coo_from_coo procedure, pass(a) :: cp_to_fmt => psb_lz_cp_coo_to_fmt @@ -380,6 +383,7 @@ module psb_z_base_mat_mod procedure, pass(a) :: fix => psb_lz_fix_coo procedure, pass(a) :: trim => psb_lz_coo_trim procedure, pass(a) :: clean_zeros => psb_lz_coo_clean_zeros + procedure, pass(a) :: clean_negidx => psb_lz_coo_clean_negidx procedure, pass(a) :: print => psb_lz_coo_print procedure, pass(a) :: free => lz_coo_free procedure, pass(a) :: mold => psb_lz_coo_mold @@ -1678,6 +1682,17 @@ module psb_z_base_mat_mod class(psb_z_coo_sparse_mat), intent(inout) :: a end subroutine psb_z_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_z_coo_sparse_mat + ! + interface + subroutine psb_z_coo_ensure_size(nz,a) + import + integer(psb_ipk_), intent(in) :: nz + class(psb_z_coo_sparse_mat), intent(inout) :: a + end subroutine psb_z_coo_ensure_size + end interface ! !> @@ -1715,6 +1730,46 @@ module psb_z_base_mat_mod end subroutine psb_z_coo_clean_zeros end interface + ! + !> + !! \memberof psb_z_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_z_coo_clean_negidx(a,info) + import + class(psb_z_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_z_coo_clean_negidx + end interface + + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_z_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + complex(psb_dpk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_z_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner + + ! !> !! \memberof psb_z_coo_sparse_mat @@ -1759,9 +1814,9 @@ module psb_z_base_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_z_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_z_coo_print end interface @@ -3279,6 +3334,17 @@ module psb_z_base_mat_mod class(psb_lz_coo_sparse_mat), intent(inout) :: a end subroutine psb_lz_coo_reallocate_nz end interface + ! + !> + !! \memberof psb_lz_coo_sparse_mat + ! + interface + subroutine psb_lz_coo_ensure_size(nz,a) + import + integer(psb_lpk_), intent(in) :: nz + class(psb_lz_coo_sparse_mat), intent(inout) :: a + end subroutine psb_lz_coo_ensure_size + end interface ! !> @@ -3316,6 +3382,46 @@ module psb_z_base_mat_mod end subroutine psb_lz_coo_clean_zeros end interface + ! + !> + !! \memberof psb_lz_coo_sparse_mat + !! \brief Take out any entries with negative row or column index + !! May happen when converting local/global numbering + !! \param info return code + !! + ! + interface + subroutine psb_lz_coo_clean_negidx(a,info) + import + class(psb_lz_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lz_coo_clean_negidx + end interface + +#if defined(IPK4) && defined(LPK8) + ! + !> Funtion: coo_clean_negidx_inner + !! \brief Take out any entries with negative row or column index + !! Used internally by coo_clean_negidx + !! \param nzin Number of entries on input to be handled + !! \param ia(:) Row indices + !! \param ja(:) Col indices + !! \param val(:) Coefficients + !! \param nzout Number of entries after sorting/duplicate handling + !! \param info return code + !! + ! + interface psb_coo_clean_negidx_inner + subroutine psb_lz_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + import + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + complex(psb_dpk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lz_coo_clean_negidx_inner + end interface psb_coo_clean_negidx_inner +#endif ! !> !! \memberof psb_lz_coo_sparse_mat @@ -3674,6 +3780,8 @@ module psb_z_base_mat_mod end subroutine psb_lz_coo_scals end interface + public :: psb_z_get_print_frmt, psb_lz_get_print_frmt + !> !! \memberof psb_lz_coo_sparse_mat !! \see psb_lz_base_mat_mod::psb_lz_base_scalplusidentity @@ -3729,6 +3837,56 @@ module psb_z_base_mat_mod contains + function psb_z_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_ipk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='complex' + integer(psb_lpk_) :: nmx + integer(psb_ipk_) :: ni + nmx = max(nr,nc,ione) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_z_get_print_frmt + + function psb_lz_get_print_frmt(nr,nc,nz,iv,ivr,ivc) result(frmt) + + implicit none + character(len=80) :: frmt + integer(psb_lpk_), intent(in) :: nr, nc, nz + integer(psb_lpk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) + ! + character(len=*), parameter :: datatype='complex' + integer(psb_lpk_) :: nmx + integer(psb_lpk_) :: ni + nmx = max(nr,nc,lone) + if (present(iv)) nmx = max(nmx,maxval(abs(iv(1:nc)))) + if (present(ivr)) nmx = max(nmx,maxval(abs(ivr(1:nr)))) + if (present(ivc)) nmx = max(nmx,maxval(abs(ivc(1:nc)))) + ni = floor(log10(1.0*nmx)) + 2 + + if (datatype=='complex') then + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' + else + write(frmt,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' + end if + + end function psb_lz_get_print_frmt + ! == ================================== ! diff --git a/base/modules/serial/psb_z_csc_mat_mod.f90 b/base/modules/serial/psb_z_csc_mat_mod.f90 index b3b3e8fe1..222742ebe 100644 --- a/base/modules/serial/psb_z_csc_mat_mod.f90 +++ b/base/modules/serial/psb_z_csc_mat_mod.f90 @@ -219,9 +219,9 @@ module psb_z_csc_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_z_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_z_csc_print end interface diff --git a/base/modules/serial/psb_z_csr_mat_mod.f90 b/base/modules/serial/psb_z_csr_mat_mod.f90 index 406ef6b4f..4ec8dd004 100644 --- a/base/modules/serial/psb_z_csr_mat_mod.f90 +++ b/base/modules/serial/psb_z_csr_mat_mod.f90 @@ -169,9 +169,9 @@ module psb_z_csr_mat_mod import integer(psb_ipk_), intent(in) :: iout class(psb_z_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_z_csr_print end interface ! diff --git a/base/modules/serial/psb_z_mat_mod.F90 b/base/modules/serial/psb_z_mat_mod.F90 index 7a32cde86..d03f3bef4 100644 --- a/base/modules/serial/psb_z_mat_mod.F90 +++ b/base/modules/serial/psb_z_mat_mod.F90 @@ -145,8 +145,9 @@ module psb_z_mat_mod procedure, pass(a) :: tril => psb_z_tril procedure, pass(a) :: triu => psb_z_triu procedure, pass(a) :: m_csclip => psb_z_csclip + procedure, pass(a) :: m_csclip_ip => psb_z_csclip_ip procedure, pass(a) :: b_csclip => psb_z_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_z_clean_zeros procedure, pass(a) :: reall => psb_z_reallocate_nz procedure, pass(a) :: get_neigh => psb_z_get_neigh @@ -342,8 +343,9 @@ module psb_z_mat_mod procedure, pass(a) :: tril => psb_lz_tril procedure, pass(a) :: triu => psb_lz_triu procedure, pass(a) :: m_csclip => psb_lz_csclip + procedure, pass(a) :: m_csclip_ip => psb_lz_csclip_ip procedure, pass(a) :: b_csclip => psb_lz_b_csclip - generic, public :: csclip => b_csclip, m_csclip + generic, public :: csclip => b_csclip, m_csclip, m_csclip_ip procedure, pass(a) :: clean_zeros => psb_lz_clean_zeros procedure, pass(a) :: reall => psb_lz_reallocate_nz procedure, pass(a) :: get_neigh => psb_lz_get_neigh @@ -573,9 +575,9 @@ module psb_z_mat_mod import :: psb_ipk_, psb_lpk_, psb_zspmat_type integer(psb_ipk_), intent(in) :: iout class(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_z_sparse_print end interface @@ -584,9 +586,9 @@ module psb_z_mat_mod import :: psb_ipk_, psb_lpk_, psb_zspmat_type character(len=*), intent(in) :: fname class(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) end subroutine psb_z_n_sparse_print end interface @@ -745,6 +747,17 @@ module psb_z_mat_mod end subroutine psb_z_csclip end interface + interface + subroutine psb_z_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_zspmat_type, psb_dpk_ + class(psb_zspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_z_csclip_ip + end interface + interface subroutine psb_z_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -1514,6 +1527,17 @@ module psb_z_mat_mod end subroutine psb_lz_csclip end interface + interface + subroutine psb_lz_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + import :: psb_ipk_, psb_lpk_, psb_lzspmat_type, psb_dpk_ + class(psb_lzspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + end subroutine psb_lz_csclip_ip + end interface + interface subroutine psb_lz_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) diff --git a/base/modules/serial/psb_z_serial_mod.f90 b/base/modules/serial/psb_z_serial_mod.f90 index 5afbcf961..dbfce00bd 100644 --- a/base/modules/serial/psb_z_serial_mod.f90 +++ b/base/modules/serial/psb_z_serial_mod.f90 @@ -292,9 +292,9 @@ contains use psb_z_mat_mod, only : psb_zspmat_type integer(psb_ipk_), intent(in) :: iout type(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(iout,iv,head,ivr,ivc) @@ -304,9 +304,9 @@ contains use psb_z_mat_mod, only : psb_zspmat_type character(len=*), intent(in) :: fname type(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:),ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:),ivc(:) call a%print(fname,iv,head,ivr,ivc) diff --git a/base/modules/tools/psb_c_tools_mod.f90 b/base/modules/tools/psb_c_tools_mod.F90 similarity index 80% rename from base/modules/tools/psb_c_tools_mod.f90 rename to base/modules/tools/psb_c_tools_mod.F90 index bf02bdc51..fdcc5e56e 100644 --- a/base/modules/tools/psb_c_tools_mod.f90 +++ b/base/modules/tools/psb_c_tools_mod.F90 @@ -32,7 +32,9 @@ Module psb_c_tools_mod use psb_desc_mod, only : psb_desc_type, psb_spk_, psb_ipk_, psb_lpk_ use psb_c_vect_mod, only : psb_c_base_vect_type, psb_c_vect_type - use psb_c_mat_mod, only : psb_cspmat_type, psb_lcspmat_type, psb_c_base_sparse_mat, psb_lc_csr_sparse_mat + use psb_c_mat_mod, only : psb_cspmat_type, psb_lcspmat_type, psb_c_base_sparse_mat, & + & psb_lc_csr_sparse_mat, psb_lc_coo_sparse_mat, & + & psb_c_csr_sparse_mat, psb_c_coo_sparse_mat use psb_l_vect_mod, only : psb_l_vect_type use psb_c_multivect_mod, only : psb_c_base_multivect_type, psb_c_multivect_type @@ -220,6 +222,18 @@ Module psb_c_tools_mod integer(psb_ipk_), intent(in), optional :: data type(psb_desc_type),Intent(in), optional, target :: col_desc end Subroutine psb_lc_csr_halo + Subroutine psb_c_lc_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + import + implicit none + type(psb_c_csr_sparse_mat),Intent(in) :: a + type(psb_lc_csr_sparse_mat),Intent(inout) :: blk + type(psb_desc_type),intent(in), target :: desc_a + integer(psb_ipk_), intent(out) :: info + logical, optional, intent(in) :: rowcnv,colcnv,rowscale,colscale,outcol_glob + integer(psb_ipk_), intent(in), optional :: data + type(psb_desc_type),Intent(in), optional, target :: col_desc + end Subroutine psb_c_lc_csr_halo end interface @@ -282,6 +296,7 @@ Module psb_c_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_cspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_cspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) import implicit none @@ -293,6 +308,7 @@ Module psb_c_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_cspins_csr_iirp +#endif subroutine psb_cspins_v(nz,ia,ja,val,a,desc_a,info,rebuild,local) use psb_i_vect_mod, only : psb_i_vect_type import @@ -332,6 +348,17 @@ Module psb_c_tools_mod end interface interface psb_par_spspmm + subroutine psb_c_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + import :: psb_c_csr_sparse_mat, psb_desc_type, psb_ipk_ + Implicit None + type(psb_c_csr_sparse_mat),intent(in) :: acsr + type(psb_c_csr_sparse_mat),intent(inout) :: bcsr + type(psb_c_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + End Subroutine psb_c_par_csr_spspmm subroutine psb_lc_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) import :: psb_lc_csr_sparse_mat, psb_desc_type, psb_ipk_ Implicit None @@ -344,5 +371,54 @@ Module psb_c_tools_mod integer(psb_ipk_), intent(in), optional :: data End Subroutine psb_lc_par_csr_spspmm end interface psb_par_spspmm + + interface psb_glob_transpose + subroutine psb_c_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_c_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_c_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_c_coo_glob_transpose + subroutine psb_lc_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_lc_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_lc_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lc_coo_glob_transpose + subroutine psb_lc_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_lcspmat_type), intent(in) :: ain + type(psb_lcspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lc_simple_glob_transpose + subroutine psb_lc_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_lcspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lc_simple_glob_transpose_ip + subroutine psb_c_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_cspmat_type), intent(in) :: ain + type(psb_cspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_c_simple_glob_transpose + subroutine psb_c_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_cspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_c_simple_glob_transpose_ip + end interface psb_glob_transpose + + end module psb_c_tools_mod diff --git a/base/modules/tools/psb_cd_tools_mod.f90 b/base/modules/tools/psb_cd_tools_mod.F90 similarity index 99% rename from base/modules/tools/psb_cd_tools_mod.f90 rename to base/modules/tools/psb_cd_tools_mod.F90 index 62d22ed34..3a67d829e 100644 --- a/base/modules/tools/psb_cd_tools_mod.f90 +++ b/base/modules/tools/psb_cd_tools_mod.F90 @@ -104,6 +104,7 @@ module psb_cd_tools_mod end interface interface psb_cdins +#if defined(IPK4) && defined(LPK8) subroutine psb_cdinsrc(nz,ia,ja,desc_a,info,ila,jla) import :: psb_ipk_, psb_lpk_, psb_desc_type type(psb_desc_type), intent(inout) :: desc_a @@ -122,6 +123,7 @@ module psb_cd_tools_mod logical, optional, target, intent(in) :: mask(:) integer(psb_ipk_), intent(in), optional :: lidx(:) end subroutine psb_cdinsc +#endif subroutine psb_lcdinsrc(nz,ia,ja,desc_a,info,ila,jla) import :: psb_ipk_, psb_lpk_, psb_desc_type type(psb_desc_type), intent(inout) :: desc_a diff --git a/base/modules/tools/psb_d_tools_mod.f90 b/base/modules/tools/psb_d_tools_mod.F90 similarity index 80% rename from base/modules/tools/psb_d_tools_mod.f90 rename to base/modules/tools/psb_d_tools_mod.F90 index faf910451..aa127872a 100644 --- a/base/modules/tools/psb_d_tools_mod.f90 +++ b/base/modules/tools/psb_d_tools_mod.F90 @@ -32,7 +32,9 @@ Module psb_d_tools_mod use psb_desc_mod, only : psb_desc_type, psb_dpk_, psb_ipk_, psb_lpk_ use psb_d_vect_mod, only : psb_d_base_vect_type, psb_d_vect_type - use psb_d_mat_mod, only : psb_dspmat_type, psb_ldspmat_type, psb_d_base_sparse_mat, psb_ld_csr_sparse_mat + use psb_d_mat_mod, only : psb_dspmat_type, psb_ldspmat_type, psb_d_base_sparse_mat, & + & psb_ld_csr_sparse_mat, psb_ld_coo_sparse_mat, & + & psb_d_csr_sparse_mat, psb_d_coo_sparse_mat use psb_l_vect_mod, only : psb_l_vect_type use psb_d_multivect_mod, only : psb_d_base_multivect_type, psb_d_multivect_type @@ -220,6 +222,18 @@ Module psb_d_tools_mod integer(psb_ipk_), intent(in), optional :: data type(psb_desc_type),Intent(in), optional, target :: col_desc end Subroutine psb_ld_csr_halo + Subroutine psb_d_ld_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + import + implicit none + type(psb_d_csr_sparse_mat),Intent(in) :: a + type(psb_ld_csr_sparse_mat),Intent(inout) :: blk + type(psb_desc_type),intent(in), target :: desc_a + integer(psb_ipk_), intent(out) :: info + logical, optional, intent(in) :: rowcnv,colcnv,rowscale,colscale,outcol_glob + integer(psb_ipk_), intent(in), optional :: data + type(psb_desc_type),Intent(in), optional, target :: col_desc + end Subroutine psb_d_ld_csr_halo end interface @@ -282,6 +296,7 @@ Module psb_d_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_dspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_dspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) import implicit none @@ -293,6 +308,7 @@ Module psb_d_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_dspins_csr_iirp +#endif subroutine psb_dspins_v(nz,ia,ja,val,a,desc_a,info,rebuild,local) use psb_i_vect_mod, only : psb_i_vect_type import @@ -332,6 +348,17 @@ Module psb_d_tools_mod end interface interface psb_par_spspmm + subroutine psb_d_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + import :: psb_d_csr_sparse_mat, psb_desc_type, psb_ipk_ + Implicit None + type(psb_d_csr_sparse_mat),intent(in) :: acsr + type(psb_d_csr_sparse_mat),intent(inout) :: bcsr + type(psb_d_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + End Subroutine psb_d_par_csr_spspmm subroutine psb_ld_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) import :: psb_ld_csr_sparse_mat, psb_desc_type, psb_ipk_ Implicit None @@ -344,5 +371,54 @@ Module psb_d_tools_mod integer(psb_ipk_), intent(in), optional :: data End Subroutine psb_ld_par_csr_spspmm end interface psb_par_spspmm + + interface psb_glob_transpose + subroutine psb_d_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_d_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_d_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_d_coo_glob_transpose + subroutine psb_ld_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_ld_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_ld_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ld_coo_glob_transpose + subroutine psb_ld_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_ldspmat_type), intent(in) :: ain + type(psb_ldspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ld_simple_glob_transpose + subroutine psb_ld_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_ldspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ld_simple_glob_transpose_ip + subroutine psb_d_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_dspmat_type), intent(in) :: ain + type(psb_dspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_d_simple_glob_transpose + subroutine psb_d_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_dspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_d_simple_glob_transpose_ip + end interface psb_glob_transpose + + end module psb_d_tools_mod diff --git a/base/modules/tools/psb_i2_tools_a_mod.f90 b/base/modules/tools/psb_i2_tools_a_mod.f90 new file mode 100644 index 000000000..860a55b16 --- /dev/null +++ b/base/modules/tools/psb_i2_tools_a_mod.f90 @@ -0,0 +1,119 @@ +! +! 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. +! +! +Module psb_i2_tools_a_mod + use psb_desc_mod, only : psb_desc_type, psb_i2pk_, psb_ipk_, psb_lpk_, psb_mpk_, psb_epk_ + + interface psb_geall + subroutine psb_i2alloc(x, desc_a, info, n, lb) + import + implicit none + integer(psb_i2pk_), allocatable, intent(out) :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: n, lb + end subroutine psb_i2alloc + subroutine psb_i2allocv(x, desc_a,info,n) + import + implicit none + integer(psb_i2pk_), allocatable, intent(out) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: n + end subroutine psb_i2allocv + end interface + + + interface psb_geasb + subroutine psb_i2asb(x, desc_a, info, scratch) + import + implicit none + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_), allocatable, intent(inout) :: x(:,:) + integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: scratch + end subroutine psb_i2asb + subroutine psb_i2asbv(x, desc_a, info, scratch) + import + implicit none + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_), allocatable, intent(inout) :: x(:) + integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: scratch + end subroutine psb_i2asbv + end interface + + interface psb_gefree + subroutine psb_i2free(x, desc_a, info) + import + implicit none + integer(psb_i2pk_),allocatable, intent(inout) :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_i2free + subroutine psb_i2freev(x, desc_a, info) + import + implicit none + integer(psb_i2pk_),allocatable, intent(inout) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_i2freev + end interface + + + interface psb_geins + subroutine psb_i2insi(m,irw,val, x, desc_a,info,dupl,local) + import + implicit none + integer(psb_ipk_), intent(in) :: m + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_),intent(inout) :: x(:,:) + integer(psb_lpk_), intent(in) :: irw(:) + integer(psb_i2pk_), intent(in) :: val(:,:) + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: dupl + logical, intent(in), optional :: local + end subroutine psb_i2insi + subroutine psb_i2insvi(m, irw,val, x,desc_a,info,dupl,local) + import + implicit none + integer(psb_ipk_), intent(in) :: m + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_),intent(inout) :: x(:) + integer(psb_lpk_), intent(in) :: irw(:) + integer(psb_i2pk_), intent(in) :: val(:) + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: dupl + logical, intent(in), optional :: local + end subroutine psb_i2insvi + end interface + +end module psb_i2_tools_a_mod diff --git a/base/modules/tools/psb_i_tools_mod.f90 b/base/modules/tools/psb_i_tools_mod.F90 similarity index 100% rename from base/modules/tools/psb_i_tools_mod.f90 rename to base/modules/tools/psb_i_tools_mod.F90 diff --git a/base/modules/tools/psb_l_tools_mod.f90 b/base/modules/tools/psb_l_tools_mod.F90 similarity index 100% rename from base/modules/tools/psb_l_tools_mod.f90 rename to base/modules/tools/psb_l_tools_mod.F90 diff --git a/base/modules/tools/psb_s_tools_mod.f90 b/base/modules/tools/psb_s_tools_mod.F90 similarity index 80% rename from base/modules/tools/psb_s_tools_mod.f90 rename to base/modules/tools/psb_s_tools_mod.F90 index 59c576a01..24453728e 100644 --- a/base/modules/tools/psb_s_tools_mod.f90 +++ b/base/modules/tools/psb_s_tools_mod.F90 @@ -32,7 +32,9 @@ Module psb_s_tools_mod use psb_desc_mod, only : psb_desc_type, psb_spk_, psb_ipk_, psb_lpk_ use psb_s_vect_mod, only : psb_s_base_vect_type, psb_s_vect_type - use psb_s_mat_mod, only : psb_sspmat_type, psb_lsspmat_type, psb_s_base_sparse_mat, psb_ls_csr_sparse_mat + use psb_s_mat_mod, only : psb_sspmat_type, psb_lsspmat_type, psb_s_base_sparse_mat, & + & psb_ls_csr_sparse_mat, psb_ls_coo_sparse_mat, & + & psb_s_csr_sparse_mat, psb_s_coo_sparse_mat use psb_l_vect_mod, only : psb_l_vect_type use psb_s_multivect_mod, only : psb_s_base_multivect_type, psb_s_multivect_type @@ -220,6 +222,18 @@ Module psb_s_tools_mod integer(psb_ipk_), intent(in), optional :: data type(psb_desc_type),Intent(in), optional, target :: col_desc end Subroutine psb_ls_csr_halo + Subroutine psb_s_ls_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + import + implicit none + type(psb_s_csr_sparse_mat),Intent(in) :: a + type(psb_ls_csr_sparse_mat),Intent(inout) :: blk + type(psb_desc_type),intent(in), target :: desc_a + integer(psb_ipk_), intent(out) :: info + logical, optional, intent(in) :: rowcnv,colcnv,rowscale,colscale,outcol_glob + integer(psb_ipk_), intent(in), optional :: data + type(psb_desc_type),Intent(in), optional, target :: col_desc + end Subroutine psb_s_ls_csr_halo end interface @@ -282,6 +296,7 @@ Module psb_s_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_sspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_sspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) import implicit none @@ -293,6 +308,7 @@ Module psb_s_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_sspins_csr_iirp +#endif subroutine psb_sspins_v(nz,ia,ja,val,a,desc_a,info,rebuild,local) use psb_i_vect_mod, only : psb_i_vect_type import @@ -332,6 +348,17 @@ Module psb_s_tools_mod end interface interface psb_par_spspmm + subroutine psb_s_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + import :: psb_s_csr_sparse_mat, psb_desc_type, psb_ipk_ + Implicit None + type(psb_s_csr_sparse_mat),intent(in) :: acsr + type(psb_s_csr_sparse_mat),intent(inout) :: bcsr + type(psb_s_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + End Subroutine psb_s_par_csr_spspmm subroutine psb_ls_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) import :: psb_ls_csr_sparse_mat, psb_desc_type, psb_ipk_ Implicit None @@ -344,5 +371,54 @@ Module psb_s_tools_mod integer(psb_ipk_), intent(in), optional :: data End Subroutine psb_ls_par_csr_spspmm end interface psb_par_spspmm + + interface psb_glob_transpose + subroutine psb_s_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_s_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_s_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_s_coo_glob_transpose + subroutine psb_ls_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_ls_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_ls_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ls_coo_glob_transpose + subroutine psb_ls_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_lsspmat_type), intent(in) :: ain + type(psb_lsspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ls_simple_glob_transpose + subroutine psb_ls_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_lsspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_ls_simple_glob_transpose_ip + subroutine psb_s_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_sspmat_type), intent(in) :: ain + type(psb_sspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_s_simple_glob_transpose + subroutine psb_s_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_sspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_s_simple_glob_transpose_ip + end interface psb_glob_transpose + + end module psb_s_tools_mod diff --git a/base/modules/tools/psb_z_tools_mod.f90 b/base/modules/tools/psb_z_tools_mod.F90 similarity index 80% rename from base/modules/tools/psb_z_tools_mod.f90 rename to base/modules/tools/psb_z_tools_mod.F90 index 185aba049..2b639fdc9 100644 --- a/base/modules/tools/psb_z_tools_mod.f90 +++ b/base/modules/tools/psb_z_tools_mod.F90 @@ -32,7 +32,9 @@ Module psb_z_tools_mod use psb_desc_mod, only : psb_desc_type, psb_dpk_, psb_ipk_, psb_lpk_ use psb_z_vect_mod, only : psb_z_base_vect_type, psb_z_vect_type - use psb_z_mat_mod, only : psb_zspmat_type, psb_lzspmat_type, psb_z_base_sparse_mat, psb_lz_csr_sparse_mat + use psb_z_mat_mod, only : psb_zspmat_type, psb_lzspmat_type, psb_z_base_sparse_mat, & + & psb_lz_csr_sparse_mat, psb_lz_coo_sparse_mat, & + & psb_z_csr_sparse_mat, psb_z_coo_sparse_mat use psb_l_vect_mod, only : psb_l_vect_type use psb_z_multivect_mod, only : psb_z_base_multivect_type, psb_z_multivect_type @@ -220,6 +222,18 @@ Module psb_z_tools_mod integer(psb_ipk_), intent(in), optional :: data type(psb_desc_type),Intent(in), optional, target :: col_desc end Subroutine psb_lz_csr_halo + Subroutine psb_z_lz_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + import + implicit none + type(psb_z_csr_sparse_mat),Intent(in) :: a + type(psb_lz_csr_sparse_mat),Intent(inout) :: blk + type(psb_desc_type),intent(in), target :: desc_a + integer(psb_ipk_), intent(out) :: info + logical, optional, intent(in) :: rowcnv,colcnv,rowscale,colscale,outcol_glob + integer(psb_ipk_), intent(in), optional :: data + type(psb_desc_type),Intent(in), optional, target :: col_desc + end Subroutine psb_z_lz_csr_halo end interface @@ -282,6 +296,7 @@ Module psb_z_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_zspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_zspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) import implicit none @@ -293,6 +308,7 @@ Module psb_z_tools_mod integer(psb_ipk_), intent(out) :: info logical, intent(in), optional :: rebuild, local end subroutine psb_zspins_csr_iirp +#endif subroutine psb_zspins_v(nz,ia,ja,val,a,desc_a,info,rebuild,local) use psb_i_vect_mod, only : psb_i_vect_type import @@ -332,6 +348,17 @@ Module psb_z_tools_mod end interface interface psb_par_spspmm + subroutine psb_z_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + import :: psb_z_csr_sparse_mat, psb_desc_type, psb_ipk_ + Implicit None + type(psb_z_csr_sparse_mat),intent(in) :: acsr + type(psb_z_csr_sparse_mat),intent(inout) :: bcsr + type(psb_z_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + End Subroutine psb_z_par_csr_spspmm subroutine psb_lz_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) import :: psb_lz_csr_sparse_mat, psb_desc_type, psb_ipk_ Implicit None @@ -344,5 +371,54 @@ Module psb_z_tools_mod integer(psb_ipk_), intent(in), optional :: data End Subroutine psb_lz_par_csr_spspmm end interface psb_par_spspmm + + interface psb_glob_transpose + subroutine psb_z_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_z_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_z_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_z_coo_glob_transpose + subroutine psb_lz_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) + import + type(psb_lz_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_lz_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lz_coo_glob_transpose + subroutine psb_lz_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_lzspmat_type), intent(in) :: ain + type(psb_lzspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lz_simple_glob_transpose + subroutine psb_lz_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_lzspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_lz_simple_glob_transpose_ip + subroutine psb_z_simple_glob_transpose(ain,aout,desc_a,info) + import + type(psb_zspmat_type), intent(in) :: ain + type(psb_zspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_z_simple_glob_transpose + subroutine psb_z_simple_glob_transpose_ip(ain,desc_a,info) + import + type(psb_zspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + end subroutine psb_z_simple_glob_transpose_ip + end interface psb_glob_transpose + + end module psb_z_tools_mod diff --git a/base/serial/Makefile b/base/serial/Makefile index 1ce9156bb..5bff0b64a 100644 --- a/base/serial/Makefile +++ b/base/serial/Makefile @@ -29,12 +29,12 @@ lib: impld sortd lib1 $(FOBJS) lib1: $(FOBJS) impld: - cd impl && $(MAKE) lib + $(MAKE) -C impl lib sortd: - cd sort && $(MAKE) lib + $(MAKE) -C sort lib clean: /bin/rm -f $(FOBJS) *$(.mod) - (cd impl; $(MAKE) clean) - (cd sort; $(MAKE) clean) + ($(MAKE) -C impl clean) + ($(MAKE) -C sort clean) veryclean: clean diff --git a/base/serial/impl/psb_c_coo_impl.f90 b/base/serial/impl/psb_c_coo_impl.F90 similarity index 97% rename from base/serial/impl/psb_c_coo_impl.f90 rename to base/serial/impl/psb_c_coo_impl.F90 index f4240d3d2..88bdb66fe 100644 --- a/base/serial/impl/psb_c_coo_impl.f90 +++ b/base/serial/impl/psb_c_coo_impl.F90 @@ -407,6 +407,38 @@ subroutine psb_c_coo_reallocate_nz(nz,a) end subroutine psb_c_coo_reallocate_nz +subroutine psb_c_coo_ensure_size(nz,a) + use psb_c_base_mat_mod, psb_protect_name => psb_c_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_ipk_), intent(in) :: nz + class(psb_c_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='c_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_c_coo_ensure_size + subroutine psb_c_coo_mold(a,b,info) use psb_c_base_mat_mod, psb_protect_name => psb_c_coo_mold use psb_error_mod @@ -540,7 +572,44 @@ subroutine psb_c_coo_clean_zeros(a, info) call a%trim() end subroutine psb_c_coo_clean_zeros +subroutine psb_c_coo_clean_negidx(a,info) + use psb_error_mod + use psb_c_base_mat_mod, psb_protect_name => psb_c_coo_clean_negidx + implicit none + class(psb_c_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_c_coo_clean_negidx + +subroutine psb_c_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_c_base_mat_mod, psb_protect_name => psb_c_coo_clean_negidx_inner + implicit none + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + complex(psb_spk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_c_coo_clean_negidx_inner subroutine psb_c_coo_allocate_mnnz(m,n,a,nz) use psb_c_base_mat_mod, psb_protect_name => psb_c_coo_allocate_mnnz @@ -610,17 +679,15 @@ subroutine psb_c_coo_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_c_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='c_coo_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -632,38 +699,29 @@ subroutine psb_c_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_c_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif @@ -1777,7 +1835,7 @@ subroutine psb_c_coo_csmm(alpha,a,x,beta,y,info,trans) end if !.....end testing on alpha - else if (ctra) then + else if (ctra) then ! if (alpha == cone) then i = 1 @@ -4910,6 +4968,38 @@ subroutine psb_lc_coo_reallocate_nz(nz,a) end subroutine psb_lc_coo_reallocate_nz +subroutine psb_lc_coo_ensure_size(nz,a) + use psb_c_base_mat_mod, psb_protect_name => psb_lc_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_lpk_), intent(in) :: nz + class(psb_lc_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='lc_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_lc_coo_ensure_size + subroutine psb_lc_coo_mold(a,b,info) use psb_c_base_mat_mod, psb_protect_name => psb_lc_coo_mold use psb_error_mod @@ -5044,7 +5134,46 @@ subroutine psb_lc_coo_clean_zeros(a, info) call a%trim() end subroutine psb_lc_coo_clean_zeros +subroutine psb_lc_coo_clean_negidx(a,info) + use psb_error_mod + use psb_c_base_mat_mod, psb_protect_name => psb_lc_coo_clean_negidx + implicit none + class(psb_lc_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_lc_coo_clean_negidx + +#if defined(IPK4) && defined(LPK8) +subroutine psb_lc_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_c_base_mat_mod, psb_protect_name => psb_lc_coo_clean_negidx_inner + implicit none + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + complex(psb_spk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_lc_coo_clean_negidx_inner +#endif subroutine psb_lc_coo_allocate_mnnz(m,n,a,nz) use psb_c_base_mat_mod, psb_protect_name => psb_lc_coo_allocate_mnnz @@ -5123,9 +5252,8 @@ subroutine psb_lc_coo_print(iout,a,iv,head,ivr,ivc) character(len=20) :: name='lc_coo_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_lpk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -5137,38 +5265,29 @@ subroutine psb_lc_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lc_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif diff --git a/base/serial/impl/psb_c_csc_impl.f90 b/base/serial/impl/psb_c_csc_impl.f90 index 62f0b738e..4769f5ff4 100644 --- a/base/serial/impl/psb_c_csc_impl.f90 +++ b/base/serial/impl/psb_c_csc_impl.f90 @@ -2706,9 +2706,9 @@ subroutine psb_c_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_c_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act integer(psb_ipk_) :: ierr(5) @@ -2716,7 +2716,7 @@ subroutine psb_c_csc_print(iout,a,iv,head,ivr,ivc) logical, parameter :: debug=.false. character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv + character(len=80) :: frmt integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz @@ -2730,47 +2730,37 @@ subroutine psb_c_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 - - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if + frmt = psb_c_get_print_frmt(nr,nc,nz,iv,ivr,ivc) write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif @@ -3064,6 +3054,7 @@ subroutine psb_lc_csc_scals(d,a,info) end subroutine psb_lc_csc_scals + function psb_lc_csc_maxval(a) result(res) use psb_error_mod use psb_c_csc_mat_mod, psb_protect_name => psb_lc_csc_maxval @@ -4563,10 +4554,8 @@ subroutine psb_lc_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: ierr(5) character(len=20) :: name='lc_csc_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -4579,47 +4568,38 @@ subroutine psb_lc_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lc_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_c_csr_impl.f90 b/base/serial/impl/psb_c_csr_impl.f90 index 2c333b38f..7b2f61a2a 100644 --- a/base/serial/impl/psb_c_csr_impl.f90 +++ b/base/serial/impl/psb_c_csr_impl.f90 @@ -1677,6 +1677,9 @@ subroutine psb_c_csr_scals(d,a,info) end subroutine psb_c_csr_scals + + + ! == =================================== ! ! @@ -2747,21 +2750,21 @@ end subroutine psb_c_csr_trim subroutine psb_c_csr_print(iout,a,iv,head,ivr,ivc) use psb_string_mod + use psb_c_base_mat_mod use psb_c_csr_mat_mod, psb_protect_name => psb_c_csr_print implicit none integer(psb_ipk_), intent(in) :: iout class(psb_c_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='c_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -2774,47 +2777,38 @@ subroutine psb_c_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_c_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif @@ -4883,9 +4877,8 @@ subroutine psb_lc_csr_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: err_act character(len=20) :: name='lc_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_lpk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -4898,47 +4891,38 @@ subroutine psb_lc_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lc_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_c_mat_impl.F90 b/base/serial/impl/psb_c_mat_impl.F90 index 5663bc29b..69c67d028 100644 --- a/base/serial/impl/psb_c_mat_impl.F90 +++ b/base/serial/impl/psb_c_mat_impl.F90 @@ -466,9 +466,9 @@ subroutine psb_c_sparse_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info character(len=20) :: name='sparse_print' @@ -500,9 +500,9 @@ subroutine psb_c_n_sparse_print(fname,a,iv,head,ivr,ivc) character(len=*), intent(in) :: fname class(psb_cspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info, iout logical :: isopen @@ -1098,6 +1098,53 @@ subroutine psb_c_csclip(a,b,info,& end subroutine psb_c_csclip +subroutine psb_c_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_c_base_mat_mod + use psb_c_mat_mod, psb_protect_name => psb_c_csclip_ip + implicit none + + class(psb_cspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_c_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_c_csclip_ip subroutine psb_c_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -2602,6 +2649,8 @@ subroutine psb_c_mv_from_lb(a,b) class(psb_cspmat_type), intent(inout) :: a class(psb_lc_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_c_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_lfmt(b,info) @@ -2618,6 +2667,7 @@ subroutine psb_c_cp_from_lb(a,b) class(psb_lc_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_c_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_lfmt(b,info) @@ -2668,6 +2718,7 @@ subroutine psb_c_mv_from_l(a,b) class(psb_lcspmat_type), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_c_csr_sparse_mat :: a%a, stat=info) call a%a%mv_from_lfmt(b%a,info) @@ -2689,6 +2740,7 @@ subroutine psb_c_cp_from_l(a,b) class(psb_lcspmat_type), intent(in) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_c_csr_sparse_mat :: a%a, stat=info) call a%a%cp_from_lfmt(b%a,info) @@ -3845,6 +3897,53 @@ subroutine psb_lc_csclip(a,b,info,& end subroutine psb_lc_csclip +subroutine psb_lc_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_c_base_mat_mod + use psb_c_mat_mod, psb_protect_name => psb_lc_csclip_ip + implicit none + + class(psb_lcspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_lc_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_lc_csclip_ip subroutine psb_lc_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -5100,6 +5199,8 @@ subroutine psb_lc_mv_from_ib(a,b) class(psb_lcspmat_type), intent(inout) :: a class(psb_c_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_lc_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_ifmt(b,info) @@ -5115,6 +5216,7 @@ subroutine psb_lc_cp_from_ib(a,b) class(psb_c_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_lc_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_ifmt(b,info) diff --git a/base/serial/impl/psb_d_coo_impl.f90 b/base/serial/impl/psb_d_coo_impl.F90 similarity index 97% rename from base/serial/impl/psb_d_coo_impl.f90 rename to base/serial/impl/psb_d_coo_impl.F90 index aeddc6f3c..cd5ea5a80 100644 --- a/base/serial/impl/psb_d_coo_impl.f90 +++ b/base/serial/impl/psb_d_coo_impl.F90 @@ -407,6 +407,38 @@ subroutine psb_d_coo_reallocate_nz(nz,a) end subroutine psb_d_coo_reallocate_nz +subroutine psb_d_coo_ensure_size(nz,a) + use psb_d_base_mat_mod, psb_protect_name => psb_d_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_ipk_), intent(in) :: nz + class(psb_d_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='d_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_d_coo_ensure_size + subroutine psb_d_coo_mold(a,b,info) use psb_d_base_mat_mod, psb_protect_name => psb_d_coo_mold use psb_error_mod @@ -540,7 +572,44 @@ subroutine psb_d_coo_clean_zeros(a, info) call a%trim() end subroutine psb_d_coo_clean_zeros +subroutine psb_d_coo_clean_negidx(a,info) + use psb_error_mod + use psb_d_base_mat_mod, psb_protect_name => psb_d_coo_clean_negidx + implicit none + class(psb_d_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_d_coo_clean_negidx + +subroutine psb_d_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_d_base_mat_mod, psb_protect_name => psb_d_coo_clean_negidx_inner + implicit none + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + real(psb_dpk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_d_coo_clean_negidx_inner subroutine psb_d_coo_allocate_mnnz(m,n,a,nz) use psb_d_base_mat_mod, psb_protect_name => psb_d_coo_allocate_mnnz @@ -610,17 +679,15 @@ subroutine psb_d_coo_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_d_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='d_coo_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -632,38 +699,29 @@ subroutine psb_d_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_d_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif @@ -1777,7 +1835,7 @@ subroutine psb_d_coo_csmm(alpha,a,x,beta,y,info,trans) end if !.....end testing on alpha - else if (ctra) then + else if (ctra) then ! if (alpha == done) then i = 1 @@ -4910,6 +4968,38 @@ subroutine psb_ld_coo_reallocate_nz(nz,a) end subroutine psb_ld_coo_reallocate_nz +subroutine psb_ld_coo_ensure_size(nz,a) + use psb_d_base_mat_mod, psb_protect_name => psb_ld_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_lpk_), intent(in) :: nz + class(psb_ld_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='ld_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_ld_coo_ensure_size + subroutine psb_ld_coo_mold(a,b,info) use psb_d_base_mat_mod, psb_protect_name => psb_ld_coo_mold use psb_error_mod @@ -5044,7 +5134,46 @@ subroutine psb_ld_coo_clean_zeros(a, info) call a%trim() end subroutine psb_ld_coo_clean_zeros +subroutine psb_ld_coo_clean_negidx(a,info) + use psb_error_mod + use psb_d_base_mat_mod, psb_protect_name => psb_ld_coo_clean_negidx + implicit none + class(psb_ld_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_ld_coo_clean_negidx + +#if defined(IPK4) && defined(LPK8) +subroutine psb_ld_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_d_base_mat_mod, psb_protect_name => psb_ld_coo_clean_negidx_inner + implicit none + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + real(psb_dpk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_ld_coo_clean_negidx_inner +#endif subroutine psb_ld_coo_allocate_mnnz(m,n,a,nz) use psb_d_base_mat_mod, psb_protect_name => psb_ld_coo_allocate_mnnz @@ -5123,9 +5252,8 @@ subroutine psb_ld_coo_print(iout,a,iv,head,ivr,ivc) character(len=20) :: name='ld_coo_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_lpk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -5137,38 +5265,29 @@ subroutine psb_ld_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ld_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif diff --git a/base/serial/impl/psb_d_csc_impl.f90 b/base/serial/impl/psb_d_csc_impl.f90 index 624332e54..eb1f2021b 100644 --- a/base/serial/impl/psb_d_csc_impl.f90 +++ b/base/serial/impl/psb_d_csc_impl.f90 @@ -2706,9 +2706,9 @@ subroutine psb_d_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_d_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act integer(psb_ipk_) :: ierr(5) @@ -2716,7 +2716,7 @@ subroutine psb_d_csc_print(iout,a,iv,head,ivr,ivc) logical, parameter :: debug=.false. character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv + character(len=80) :: frmt integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz @@ -2730,47 +2730,37 @@ subroutine psb_d_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 - - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if + frmt = psb_d_get_print_frmt(nr,nc,nz,iv,ivr,ivc) write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif @@ -3064,6 +3054,7 @@ subroutine psb_ld_csc_scals(d,a,info) end subroutine psb_ld_csc_scals + function psb_ld_csc_maxval(a) result(res) use psb_error_mod use psb_d_csc_mat_mod, psb_protect_name => psb_ld_csc_maxval @@ -4563,10 +4554,8 @@ subroutine psb_ld_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: ierr(5) character(len=20) :: name='ld_csc_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -4579,47 +4568,38 @@ subroutine psb_ld_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ld_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_d_csr_impl.f90 b/base/serial/impl/psb_d_csr_impl.f90 index 1a99ae9ab..01f36eaab 100644 --- a/base/serial/impl/psb_d_csr_impl.f90 +++ b/base/serial/impl/psb_d_csr_impl.f90 @@ -1677,6 +1677,9 @@ subroutine psb_d_csr_scals(d,a,info) end subroutine psb_d_csr_scals + + + ! == =================================== ! ! @@ -2747,21 +2750,21 @@ end subroutine psb_d_csr_trim subroutine psb_d_csr_print(iout,a,iv,head,ivr,ivc) use psb_string_mod + use psb_d_base_mat_mod use psb_d_csr_mat_mod, psb_protect_name => psb_d_csr_print implicit none integer(psb_ipk_), intent(in) :: iout class(psb_d_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='d_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -2774,47 +2777,38 @@ subroutine psb_d_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_d_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif @@ -4883,9 +4877,8 @@ subroutine psb_ld_csr_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: err_act character(len=20) :: name='ld_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_lpk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -4898,47 +4891,38 @@ subroutine psb_ld_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ld_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_d_mat_impl.F90 b/base/serial/impl/psb_d_mat_impl.F90 index c8288a719..86de55367 100644 --- a/base/serial/impl/psb_d_mat_impl.F90 +++ b/base/serial/impl/psb_d_mat_impl.F90 @@ -466,9 +466,9 @@ subroutine psb_d_sparse_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info character(len=20) :: name='sparse_print' @@ -500,9 +500,9 @@ subroutine psb_d_n_sparse_print(fname,a,iv,head,ivr,ivc) character(len=*), intent(in) :: fname class(psb_dspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info, iout logical :: isopen @@ -1098,6 +1098,53 @@ subroutine psb_d_csclip(a,b,info,& end subroutine psb_d_csclip +subroutine psb_d_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_d_base_mat_mod + use psb_d_mat_mod, psb_protect_name => psb_d_csclip_ip + implicit none + + class(psb_dspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_d_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_d_csclip_ip subroutine psb_d_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -2602,6 +2649,8 @@ subroutine psb_d_mv_from_lb(a,b) class(psb_dspmat_type), intent(inout) :: a class(psb_ld_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_d_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_lfmt(b,info) @@ -2618,6 +2667,7 @@ subroutine psb_d_cp_from_lb(a,b) class(psb_ld_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_d_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_lfmt(b,info) @@ -2668,6 +2718,7 @@ subroutine psb_d_mv_from_l(a,b) class(psb_ldspmat_type), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_d_csr_sparse_mat :: a%a, stat=info) call a%a%mv_from_lfmt(b%a,info) @@ -2689,6 +2740,7 @@ subroutine psb_d_cp_from_l(a,b) class(psb_ldspmat_type), intent(in) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_d_csr_sparse_mat :: a%a, stat=info) call a%a%cp_from_lfmt(b%a,info) @@ -3845,6 +3897,53 @@ subroutine psb_ld_csclip(a,b,info,& end subroutine psb_ld_csclip +subroutine psb_ld_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_d_base_mat_mod + use psb_d_mat_mod, psb_protect_name => psb_ld_csclip_ip + implicit none + + class(psb_ldspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_ld_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_ld_csclip_ip subroutine psb_ld_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -5100,6 +5199,8 @@ subroutine psb_ld_mv_from_ib(a,b) class(psb_ldspmat_type), intent(inout) :: a class(psb_d_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_ld_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_ifmt(b,info) @@ -5115,6 +5216,7 @@ subroutine psb_ld_cp_from_ib(a,b) class(psb_d_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_ld_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_ifmt(b,info) diff --git a/base/serial/impl/psb_s_coo_impl.f90 b/base/serial/impl/psb_s_coo_impl.F90 similarity index 97% rename from base/serial/impl/psb_s_coo_impl.f90 rename to base/serial/impl/psb_s_coo_impl.F90 index 31d7995e2..061fb9045 100644 --- a/base/serial/impl/psb_s_coo_impl.f90 +++ b/base/serial/impl/psb_s_coo_impl.F90 @@ -407,6 +407,38 @@ subroutine psb_s_coo_reallocate_nz(nz,a) end subroutine psb_s_coo_reallocate_nz +subroutine psb_s_coo_ensure_size(nz,a) + use psb_s_base_mat_mod, psb_protect_name => psb_s_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_ipk_), intent(in) :: nz + class(psb_s_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='s_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_s_coo_ensure_size + subroutine psb_s_coo_mold(a,b,info) use psb_s_base_mat_mod, psb_protect_name => psb_s_coo_mold use psb_error_mod @@ -540,7 +572,44 @@ subroutine psb_s_coo_clean_zeros(a, info) call a%trim() end subroutine psb_s_coo_clean_zeros +subroutine psb_s_coo_clean_negidx(a,info) + use psb_error_mod + use psb_s_base_mat_mod, psb_protect_name => psb_s_coo_clean_negidx + implicit none + class(psb_s_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_s_coo_clean_negidx + +subroutine psb_s_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_s_base_mat_mod, psb_protect_name => psb_s_coo_clean_negidx_inner + implicit none + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + real(psb_spk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_s_coo_clean_negidx_inner subroutine psb_s_coo_allocate_mnnz(m,n,a,nz) use psb_s_base_mat_mod, psb_protect_name => psb_s_coo_allocate_mnnz @@ -610,17 +679,15 @@ subroutine psb_s_coo_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_s_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='s_coo_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -632,38 +699,29 @@ subroutine psb_s_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_s_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif @@ -1777,7 +1835,7 @@ subroutine psb_s_coo_csmm(alpha,a,x,beta,y,info,trans) end if !.....end testing on alpha - else if (ctra) then + else if (ctra) then ! if (alpha == sone) then i = 1 @@ -4910,6 +4968,38 @@ subroutine psb_ls_coo_reallocate_nz(nz,a) end subroutine psb_ls_coo_reallocate_nz +subroutine psb_ls_coo_ensure_size(nz,a) + use psb_s_base_mat_mod, psb_protect_name => psb_ls_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_lpk_), intent(in) :: nz + class(psb_ls_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='ls_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_ls_coo_ensure_size + subroutine psb_ls_coo_mold(a,b,info) use psb_s_base_mat_mod, psb_protect_name => psb_ls_coo_mold use psb_error_mod @@ -5044,7 +5134,46 @@ subroutine psb_ls_coo_clean_zeros(a, info) call a%trim() end subroutine psb_ls_coo_clean_zeros +subroutine psb_ls_coo_clean_negidx(a,info) + use psb_error_mod + use psb_s_base_mat_mod, psb_protect_name => psb_ls_coo_clean_negidx + implicit none + class(psb_ls_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_ls_coo_clean_negidx + +#if defined(IPK4) && defined(LPK8) +subroutine psb_ls_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_s_base_mat_mod, psb_protect_name => psb_ls_coo_clean_negidx_inner + implicit none + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + real(psb_spk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_ls_coo_clean_negidx_inner +#endif subroutine psb_ls_coo_allocate_mnnz(m,n,a,nz) use psb_s_base_mat_mod, psb_protect_name => psb_ls_coo_allocate_mnnz @@ -5123,9 +5252,8 @@ subroutine psb_ls_coo_print(iout,a,iv,head,ivr,ivc) character(len=20) :: name='ls_coo_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_lpk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -5137,38 +5265,29 @@ subroutine psb_ls_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ls_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif diff --git a/base/serial/impl/psb_s_csc_impl.f90 b/base/serial/impl/psb_s_csc_impl.f90 index 40eeb40ef..71e240513 100644 --- a/base/serial/impl/psb_s_csc_impl.f90 +++ b/base/serial/impl/psb_s_csc_impl.f90 @@ -2706,9 +2706,9 @@ subroutine psb_s_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_s_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act integer(psb_ipk_) :: ierr(5) @@ -2716,7 +2716,7 @@ subroutine psb_s_csc_print(iout,a,iv,head,ivr,ivc) logical, parameter :: debug=.false. character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv + character(len=80) :: frmt integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz @@ -2730,47 +2730,37 @@ subroutine psb_s_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 - - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if + frmt = psb_s_get_print_frmt(nr,nc,nz,iv,ivr,ivc) write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif @@ -3064,6 +3054,7 @@ subroutine psb_ls_csc_scals(d,a,info) end subroutine psb_ls_csc_scals + function psb_ls_csc_maxval(a) result(res) use psb_error_mod use psb_s_csc_mat_mod, psb_protect_name => psb_ls_csc_maxval @@ -4563,10 +4554,8 @@ subroutine psb_ls_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: ierr(5) character(len=20) :: name='ls_csc_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -4579,47 +4568,38 @@ subroutine psb_ls_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ls_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_s_csr_impl.f90 b/base/serial/impl/psb_s_csr_impl.f90 index d60af4f49..2fa87adf6 100644 --- a/base/serial/impl/psb_s_csr_impl.f90 +++ b/base/serial/impl/psb_s_csr_impl.f90 @@ -1677,6 +1677,9 @@ subroutine psb_s_csr_scals(d,a,info) end subroutine psb_s_csr_scals + + + ! == =================================== ! ! @@ -2747,21 +2750,21 @@ end subroutine psb_s_csr_trim subroutine psb_s_csr_print(iout,a,iv,head,ivr,ivc) use psb_string_mod + use psb_s_base_mat_mod use psb_s_csr_mat_mod, psb_protect_name => psb_s_csr_print implicit none integer(psb_ipk_), intent(in) :: iout class(psb_s_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='s_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_ipk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -2774,47 +2777,38 @@ subroutine psb_s_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_s_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif @@ -4883,9 +4877,8 @@ subroutine psb_ls_csr_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: err_act character(len=20) :: name='ls_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='real' - character(len=80) :: frmtv - integer(psb_lpk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate real general' @@ -4898,47 +4891,38 @@ subroutine psb_ls_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_ls_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_s_mat_impl.F90 b/base/serial/impl/psb_s_mat_impl.F90 index 65deb5a72..867f9fa4c 100644 --- a/base/serial/impl/psb_s_mat_impl.F90 +++ b/base/serial/impl/psb_s_mat_impl.F90 @@ -466,9 +466,9 @@ subroutine psb_s_sparse_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info character(len=20) :: name='sparse_print' @@ -500,9 +500,9 @@ subroutine psb_s_n_sparse_print(fname,a,iv,head,ivr,ivc) character(len=*), intent(in) :: fname class(psb_sspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info, iout logical :: isopen @@ -1098,6 +1098,53 @@ subroutine psb_s_csclip(a,b,info,& end subroutine psb_s_csclip +subroutine psb_s_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_s_base_mat_mod + use psb_s_mat_mod, psb_protect_name => psb_s_csclip_ip + implicit none + + class(psb_sspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_s_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_s_csclip_ip subroutine psb_s_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -2602,6 +2649,8 @@ subroutine psb_s_mv_from_lb(a,b) class(psb_sspmat_type), intent(inout) :: a class(psb_ls_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_s_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_lfmt(b,info) @@ -2618,6 +2667,7 @@ subroutine psb_s_cp_from_lb(a,b) class(psb_ls_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_s_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_lfmt(b,info) @@ -2668,6 +2718,7 @@ subroutine psb_s_mv_from_l(a,b) class(psb_lsspmat_type), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_s_csr_sparse_mat :: a%a, stat=info) call a%a%mv_from_lfmt(b%a,info) @@ -2689,6 +2740,7 @@ subroutine psb_s_cp_from_l(a,b) class(psb_lsspmat_type), intent(in) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_s_csr_sparse_mat :: a%a, stat=info) call a%a%cp_from_lfmt(b%a,info) @@ -3845,6 +3897,53 @@ subroutine psb_ls_csclip(a,b,info,& end subroutine psb_ls_csclip +subroutine psb_ls_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_s_base_mat_mod + use psb_s_mat_mod, psb_protect_name => psb_ls_csclip_ip + implicit none + + class(psb_lsspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_ls_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_ls_csclip_ip subroutine psb_ls_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -5100,6 +5199,8 @@ subroutine psb_ls_mv_from_ib(a,b) class(psb_lsspmat_type), intent(inout) :: a class(psb_s_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_ls_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_ifmt(b,info) @@ -5115,6 +5216,7 @@ subroutine psb_ls_cp_from_ib(a,b) class(psb_s_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_ls_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_ifmt(b,info) diff --git a/base/serial/impl/psb_z_coo_impl.f90 b/base/serial/impl/psb_z_coo_impl.F90 similarity index 97% rename from base/serial/impl/psb_z_coo_impl.f90 rename to base/serial/impl/psb_z_coo_impl.F90 index b950ed195..2da382963 100644 --- a/base/serial/impl/psb_z_coo_impl.f90 +++ b/base/serial/impl/psb_z_coo_impl.F90 @@ -407,6 +407,38 @@ subroutine psb_z_coo_reallocate_nz(nz,a) end subroutine psb_z_coo_reallocate_nz +subroutine psb_z_coo_ensure_size(nz,a) + use psb_z_base_mat_mod, psb_protect_name => psb_z_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_ipk_), intent(in) :: nz + class(psb_z_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='z_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_z_coo_ensure_size + subroutine psb_z_coo_mold(a,b,info) use psb_z_base_mat_mod, psb_protect_name => psb_z_coo_mold use psb_error_mod @@ -540,7 +572,44 @@ subroutine psb_z_coo_clean_zeros(a, info) call a%trim() end subroutine psb_z_coo_clean_zeros +subroutine psb_z_coo_clean_negidx(a,info) + use psb_error_mod + use psb_z_base_mat_mod, psb_protect_name => psb_z_coo_clean_negidx + implicit none + class(psb_z_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_z_coo_clean_negidx + +subroutine psb_z_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_z_base_mat_mod, psb_protect_name => psb_z_coo_clean_negidx_inner + implicit none + integer(psb_ipk_), intent(in) :: nzin + integer(psb_ipk_), intent(inout) :: ia(:), ja(:) + complex(psb_dpk_), intent(inout) :: val(:) + integer(psb_ipk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_ipk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_z_coo_clean_negidx_inner subroutine psb_z_coo_allocate_mnnz(m,n,a,nz) use psb_z_base_mat_mod, psb_protect_name => psb_z_coo_allocate_mnnz @@ -610,17 +679,15 @@ subroutine psb_z_coo_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_z_coo_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='z_coo_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -632,38 +699,29 @@ subroutine psb_z_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_z_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif @@ -1777,7 +1835,7 @@ subroutine psb_z_coo_csmm(alpha,a,x,beta,y,info,trans) end if !.....end testing on alpha - else if (ctra) then + else if (ctra) then ! if (alpha == zone) then i = 1 @@ -4910,6 +4968,38 @@ subroutine psb_lz_coo_reallocate_nz(nz,a) end subroutine psb_lz_coo_reallocate_nz +subroutine psb_lz_coo_ensure_size(nz,a) + use psb_z_base_mat_mod, psb_protect_name => psb_lz_coo_ensure_size + use psb_error_mod + use psb_realloc_mod + implicit none + integer(psb_lpk_), intent(in) :: nz + class(psb_lz_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_) :: err_act, info, nz_ + character(len=20) :: name='lz_coo_ensure_size' + logical, parameter :: debug=.false. + + call psb_erractionsave(err_act) + + nz_ = max(nz,ione) + call psb_ensure_size(nz_,a%ia,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%ja,info) + if (info == psb_success_) call psb_ensure_size(nz_,a%val,info) + + if (info /= psb_success_) then + call psb_errpush(psb_err_alloc_dealloc_,name) + goto 9999 + end if + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_lz_coo_ensure_size + subroutine psb_lz_coo_mold(a,b,info) use psb_z_base_mat_mod, psb_protect_name => psb_lz_coo_mold use psb_error_mod @@ -5044,7 +5134,46 @@ subroutine psb_lz_coo_clean_zeros(a, info) call a%trim() end subroutine psb_lz_coo_clean_zeros +subroutine psb_lz_coo_clean_negidx(a,info) + use psb_error_mod + use psb_z_base_mat_mod, psb_protect_name => psb_lz_coo_clean_negidx + implicit none + class(psb_lz_coo_sparse_mat), intent(inout) :: a + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: nz + call psb_coo_clean_negidx_inner(a%get_nzeros(),a%ia,a%ja,a%val,nz,info) + if (info == 0) call a%set_nzeros(nz) +end subroutine psb_lz_coo_clean_negidx + +#if defined(IPK4) && defined(LPK8) +subroutine psb_lz_coo_clean_negidx_inner(nzin,ia,ja,val,nzout,info) + use psb_error_mod + use psb_z_base_mat_mod, psb_protect_name => psb_lz_coo_clean_negidx_inner + implicit none + integer(psb_lpk_), intent(in) :: nzin + integer(psb_lpk_), intent(inout) :: ia(:), ja(:) + complex(psb_dpk_), intent(inout) :: val(:) + integer(psb_lpk_), intent(out) :: nzout + integer(psb_ipk_), intent(out) :: info + ! + ! + integer(psb_lpk_) :: i + info = 0 + nzout = 0 + do i=1, nzin + if ((ia(i)>0).and.(ja(i)>0)) then + nzout = nzout + 1 + val(nzout) = val(i) + ia(nzout) = ia(i) + ja(nzout) = ja(i) + end if + end do + +end subroutine psb_lz_coo_clean_negidx_inner +#endif subroutine psb_lz_coo_allocate_mnnz(m,n,a,nz) use psb_z_base_mat_mod, psb_protect_name => psb_lz_coo_allocate_mnnz @@ -5123,9 +5252,8 @@ subroutine psb_lz_coo_print(iout,a,iv,head,ivr,ivc) character(len=20) :: name='lz_coo_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_lpk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' if (present(head)) write(iout,'(a,a)') '% ',head @@ -5137,38 +5265,29 @@ subroutine psb_lz_coo_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lz_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do j=1,a%get_nzeros() - write(iout,frmtv) iv(a%ia(j)),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(a%ja(j)),a%val(j) enddo else if (present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),a%ja(j),a%val(j) + write(iout,frmt) ivr(a%ia(j)),a%ja(j),a%val(j) enddo else if (present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),ivc(a%ja(j)),a%val(j) + write(iout,frmt) a%ia(j),ivc(a%ja(j)),a%val(j) enddo else if (.not.present(ivr).and..not.present(ivc)) then do j=1,a%get_nzeros() - write(iout,frmtv) a%ia(j),a%ja(j),a%val(j) + write(iout,frmt) a%ia(j),a%ja(j),a%val(j) enddo endif endif diff --git a/base/serial/impl/psb_z_csc_impl.f90 b/base/serial/impl/psb_z_csc_impl.f90 index 3cde422fb..e1c003d0f 100644 --- a/base/serial/impl/psb_z_csc_impl.f90 +++ b/base/serial/impl/psb_z_csc_impl.f90 @@ -2706,9 +2706,9 @@ subroutine psb_z_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_z_csc_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act integer(psb_ipk_) :: ierr(5) @@ -2716,7 +2716,7 @@ subroutine psb_z_csc_print(iout,a,iv,head,ivr,ivc) logical, parameter :: debug=.false. character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv + character(len=80) :: frmt integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz @@ -2730,47 +2730,37 @@ subroutine psb_z_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 - - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if + frmt = psb_z_get_print_frmt(nr,nc,nz,iv,ivr,ivc) write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif @@ -3064,6 +3054,7 @@ subroutine psb_lz_csc_scals(d,a,info) end subroutine psb_lz_csc_scals + function psb_lz_csc_maxval(a) result(res) use psb_error_mod use psb_z_csc_mat_mod, psb_protect_name => psb_lz_csc_maxval @@ -4563,10 +4554,8 @@ subroutine psb_lz_csc_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: ierr(5) character(len=20) :: name='lz_csc_print' logical, parameter :: debug=.false. - - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -4579,47 +4568,38 @@ subroutine psb_lz_csc_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lz_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) iv(a%ia(j)),iv(i),a%val(j) + write(iout,frmt) iv(a%ia(j)),iv(i),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),i,a%val(j) + write(iout,frmt) ivr(a%ia(j)),i,a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) ivr(a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) ivr(a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),ivc(i),a%val(j) + write(iout,frmt) (a%ia(j)),ivc(i),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nc do j=a%icp(i),a%icp(i+1)-1 - write(iout,frmtv) (a%ia(j)),(i),a%val(j) + write(iout,frmt) (a%ia(j)),(i),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_z_csr_impl.f90 b/base/serial/impl/psb_z_csr_impl.f90 index 43b40b3a8..f3b7b45f9 100644 --- a/base/serial/impl/psb_z_csr_impl.f90 +++ b/base/serial/impl/psb_z_csr_impl.f90 @@ -1677,6 +1677,9 @@ subroutine psb_z_csr_scals(d,a,info) end subroutine psb_z_csr_scals + + + ! == =================================== ! ! @@ -2747,21 +2750,21 @@ end subroutine psb_z_csr_trim subroutine psb_z_csr_print(iout,a,iv,head,ivr,ivc) use psb_string_mod + use psb_z_base_mat_mod use psb_z_csr_mat_mod, psb_protect_name => psb_z_csr_print implicit none integer(psb_ipk_), intent(in) :: iout class(psb_z_csr_sparse_mat), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act character(len=20) :: name='z_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_ipk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_ipk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -2774,47 +2777,38 @@ subroutine psb_z_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_z_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif @@ -4883,9 +4877,8 @@ subroutine psb_lz_csr_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_) :: err_act character(len=20) :: name='lz_csr_print' logical, parameter :: debug=.false. - character(len=*), parameter :: datatype='complex' - character(len=80) :: frmtv - integer(psb_lpk_) :: irs,ics,i,j, nmx, ni, nr, nc, nz + character(len=80) :: frmt + integer(psb_lpk_) :: irs,ics,i,j, ni, nr, nc, nz write(iout,'(a)') '%%MatrixMarket matrix coordinate complex general' @@ -4898,47 +4891,38 @@ subroutine psb_lz_csr_print(iout,a,iv,head,ivr,ivc) nr = a%get_nrows() nc = a%get_ncols() nz = a%get_nzeros() - nmx = max(nr,nc,1) - if (present(iv)) nmx = max(nmx,maxval(abs(iv))) - if (present(ivr)) nmx = max(nmx,maxval(abs(ivr))) - if (present(ivc)) nmx = max(nmx,maxval(abs(ivc))) - ni = floor(log10(1.0*nmx)) + 1 + frmt = psb_lz_get_print_frmt(nr,nc,nz,iv,ivr,ivc) - if (datatype=='real') then - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),es26.18,1x,2(i',ni,',1x))' - else - write(frmtv,'(a,i3.3,a,i3.3,a)') '(2(i',ni,',1x),2(es26.18,1x),2(i',ni,',1x))' - end if write(iout,*) nr, nc, nz if(present(iv)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) iv(i),iv(a%ja(j)),a%val(j) + write(iout,frmt) iv(i),iv(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),(a%ja(j)),a%val(j) end do enddo else if (present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) ivr(i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) ivr(i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),ivc(a%ja(j)),a%val(j) + write(iout,frmt) (i),ivc(a%ja(j)),a%val(j) end do enddo else if (.not.present(ivr).and..not.present(ivc)) then do i=1, nr do j=a%irp(i),a%irp(i+1)-1 - write(iout,frmtv) (i),(a%ja(j)),a%val(j) + write(iout,frmt) (i),(a%ja(j)),a%val(j) end do enddo endif diff --git a/base/serial/impl/psb_z_mat_impl.F90 b/base/serial/impl/psb_z_mat_impl.F90 index ed16fdeca..07616c05d 100644 --- a/base/serial/impl/psb_z_mat_impl.F90 +++ b/base/serial/impl/psb_z_mat_impl.F90 @@ -466,9 +466,9 @@ subroutine psb_z_sparse_print(iout,a,iv,head,ivr,ivc) integer(psb_ipk_), intent(in) :: iout class(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info character(len=20) :: name='sparse_print' @@ -500,9 +500,9 @@ subroutine psb_z_n_sparse_print(fname,a,iv,head,ivr,ivc) character(len=*), intent(in) :: fname class(psb_zspmat_type), intent(in) :: a - integer(psb_ipk_), intent(in), optional :: iv(:) + integer(psb_lpk_), intent(in), optional :: iv(:) character(len=*), optional :: head - integer(psb_ipk_), intent(in), optional :: ivr(:), ivc(:) + integer(psb_lpk_), intent(in), optional :: ivr(:), ivc(:) integer(psb_ipk_) :: err_act, info, iout logical :: isopen @@ -1098,6 +1098,53 @@ subroutine psb_z_csclip(a,b,info,& end subroutine psb_z_csclip +subroutine psb_z_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_z_base_mat_mod + use psb_z_mat_mod, psb_protect_name => psb_z_csclip_ip + implicit none + + class(psb_zspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_z_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_z_csclip_ip subroutine psb_z_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -2602,6 +2649,8 @@ subroutine psb_z_mv_from_lb(a,b) class(psb_zspmat_type), intent(inout) :: a class(psb_lz_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_z_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_lfmt(b,info) @@ -2618,6 +2667,7 @@ subroutine psb_z_cp_from_lb(a,b) class(psb_lz_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_z_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_lfmt(b,info) @@ -2668,6 +2718,7 @@ subroutine psb_z_mv_from_l(a,b) class(psb_lzspmat_type), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_z_csr_sparse_mat :: a%a, stat=info) call a%a%mv_from_lfmt(b%a,info) @@ -2689,6 +2740,7 @@ subroutine psb_z_cp_from_l(a,b) class(psb_lzspmat_type), intent(in) :: b integer(psb_ipk_) :: info + info = psb_success_ if (allocated(b%a)) then if (.not.allocated(a%a)) allocate(psb_z_csr_sparse_mat :: a%a, stat=info) call a%a%cp_from_lfmt(b%a,info) @@ -3845,6 +3897,53 @@ subroutine psb_lz_csclip(a,b,info,& end subroutine psb_lz_csclip +subroutine psb_lz_csclip_ip(a,info,& + & imin,imax,jmin,jmax,rscale,cscale) + ! Output is always in COO format + use psb_error_mod + use psb_const_mod + use psb_z_base_mat_mod + use psb_z_mat_mod, psb_protect_name => psb_lz_csclip_ip + implicit none + + class(psb_lzspmat_type), intent(inout) :: a + integer(psb_ipk_),intent(out) :: info + integer(psb_lpk_), intent(in), optional :: imin,imax,jmin,jmax + logical, intent(in), optional :: rscale,cscale + + integer(psb_ipk_) :: err_act + character(len=20) :: name='csclip' + logical, parameter :: debug=.false. + type(psb_lz_coo_sparse_mat), allocatable :: acoo + + info = psb_success_ + call psb_erractionsave(err_act) + if (a%is_null()) then + info = psb_err_invalid_mat_state_ + call psb_errpush(info,name) + goto 9999 + endif + + allocate(acoo,stat=info) + if (info == psb_success_) then + call a%a%csclip(acoo,info,& + & imin,imax,jmin,jmax,rscale,cscale) + else + info = psb_err_alloc_dealloc_ + end if + if (info == psb_success_) call a%free() + if (info == psb_success_) call move_alloc(acoo,a%a) + if (info /= psb_success_) goto 9999 + + call psb_erractionrestore(err_act) + return + + +9999 call psb_error_handler(err_act) + + return + +end subroutine psb_lz_csclip_ip subroutine psb_lz_b_csclip(a,b,info,& & imin,imax,jmin,jmax,rscale,cscale) @@ -5100,6 +5199,8 @@ subroutine psb_lz_mv_from_ib(a,b) class(psb_lzspmat_type), intent(inout) :: a class(psb_z_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_lz_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%mv_from_ifmt(b,info) @@ -5115,6 +5216,7 @@ subroutine psb_lz_cp_from_ib(a,b) class(psb_z_base_sparse_mat), intent(inout) :: b integer(psb_ipk_) :: info + info = psb_success_ if (.not.allocated(a%a)) allocate(psb_lz_csr_sparse_mat :: a%a, stat=info) if (info == psb_success_) call a%a%cp_from_ifmt(b,info) diff --git a/base/serial/psb_crwextd.f90 b/base/serial/psb_crwextd.f90 index 7673a9353..1b55e4dbc 100644 --- a/base/serial/psb_crwextd.f90 +++ b/base/serial/psb_crwextd.f90 @@ -121,8 +121,9 @@ subroutine psb_cbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -137,16 +138,12 @@ subroutine psb_cbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_c_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -175,7 +172,7 @@ subroutine psb_cbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_c_coo_sparse_mat) @@ -326,8 +323,9 @@ subroutine psb_lcbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -342,16 +340,12 @@ subroutine psb_lcbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_lc_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -380,7 +374,7 @@ subroutine psb_lcbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_lc_coo_sparse_mat) diff --git a/base/serial/psb_drwextd.f90 b/base/serial/psb_drwextd.f90 index 5a5efae34..9abc42d2e 100644 --- a/base/serial/psb_drwextd.f90 +++ b/base/serial/psb_drwextd.f90 @@ -121,8 +121,9 @@ subroutine psb_dbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -137,16 +138,12 @@ subroutine psb_dbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_d_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -175,7 +172,7 @@ subroutine psb_dbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_d_coo_sparse_mat) @@ -326,8 +323,9 @@ subroutine psb_ldbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -342,16 +340,12 @@ subroutine psb_ldbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_ld_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -380,7 +374,7 @@ subroutine psb_ldbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_ld_coo_sparse_mat) diff --git a/base/serial/psb_srwextd.f90 b/base/serial/psb_srwextd.f90 index f92f39700..eb7ecf003 100644 --- a/base/serial/psb_srwextd.f90 +++ b/base/serial/psb_srwextd.f90 @@ -121,8 +121,9 @@ subroutine psb_sbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -137,16 +138,12 @@ subroutine psb_sbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_s_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -175,7 +172,7 @@ subroutine psb_sbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_s_coo_sparse_mat) @@ -326,8 +323,9 @@ subroutine psb_lsbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -342,16 +340,12 @@ subroutine psb_lsbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_ls_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -380,7 +374,7 @@ subroutine psb_lsbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_ls_coo_sparse_mat) diff --git a/base/serial/psb_zrwextd.f90 b/base/serial/psb_zrwextd.f90 index 0ea0bf3d4..f3e07f26e 100644 --- a/base/serial/psb_zrwextd.f90 +++ b/base/serial/psb_zrwextd.f90 @@ -121,8 +121,9 @@ subroutine psb_zbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -137,16 +138,12 @@ subroutine psb_zbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_z_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -175,7 +172,7 @@ subroutine psb_zbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_z_coo_sparse_mat) @@ -326,8 +323,9 @@ subroutine psb_lzbase_rwextd(nr,a,info,b,rowscale) rowscale_ = .true. end if - ma = a%get_nrows() - na = a%get_ncols() + ma = a%get_nrows() + na = a%get_ncols() + nza = a%get_nzeros() select type(a) @@ -342,16 +340,12 @@ subroutine psb_lzbase_rwextd(nr,a,info,b,rowscale) select type (b) type is (psb_lz_csr_sparse_mat) - call psb_ensure_size(size(a%ja)+nzb,a%ja,info) - call psb_ensure_size(size(a%val)+nzb,a%val,info) + call psb_ensure_size(nza+nzb,a%ja,info) + call psb_ensure_size(nza+nzb,a%val,info) + a%ja(nza+1:nza+nzb) = b%ja(1:nzb) + a%val(nza+1:nza+nzb) = b%val(1:nzb) do i=1, min(nr-ma,mb) a%irp(ma+i+1) = a%irp(ma+i) + b%irp(i+1) - b%irp(i) - ja = a%irp(ma+i) - do jb = b%irp(i), b%irp(i+1)-1 - a%val(ja) = b%val(jb) - a%ja(ja) = b%ja(jb) - ja = ja + 1 - end do end do do j=i,nr-ma a%irp(ma+j+1) = a%irp(ma+j) @@ -380,7 +374,7 @@ subroutine psb_lzbase_rwextd(nr,a,info,b,rowscale) mb = b%get_nrows() nb = b%get_ncols() nzb = b%get_nzeros() - call a%reallocate(nza+nzb) + call a%ensure_size(nza+nzb) select type(b) type is (psb_lz_coo_sparse_mat) diff --git a/base/serial/psi_i2_serial_impl.f90 b/base/serial/psi_i2_serial_impl.f90 new file mode 100644 index 000000000..59d579f2e --- /dev/null +++ b/base/serial/psi_i2_serial_impl.f90 @@ -0,0 +1,840 @@ +! +! 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. +! +! +subroutine psi_i2axpby(m,n,alpha, x, beta, y, info) + + use psb_const_mod + use psb_error_mod + implicit none + integer(psb_ipk_), intent(in) :: m, n + integer(psb_i2pk_), intent (in) :: x(:,:) + integer(psb_i2pk_), intent (inout) :: y(:,:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_) :: err_act + integer(psb_ipk_) :: lx, ly + integer(psb_ipk_) :: ierr(5) + character(len=20) :: name, ch_err + + name='psb_geaxpby' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (m < 0) then + info = psb_err_iarg_neg_ + ierr(1) = 1; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + if (n < 0) then + info = psb_err_iarg_neg_ + ierr(1) = 2; ierr(2) = n + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + lx = size(x,1) + ly = size(y,1) + if (lx < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 4; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + if (ly < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 6; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + + if ((m>0).and.(n>0)) call i2axpby(m,n,alpha,x,lx,beta,y,ly,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return +end subroutine psi_i2axpby + +subroutine psi_i2axpbyv(m,alpha, x, beta, y, info) + + use psb_const_mod + use psb_error_mod + implicit none + integer(psb_ipk_), intent(in) :: m + integer(psb_i2pk_), intent (in) :: x(:) + integer(psb_i2pk_), intent (inout) :: y(:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_) :: err_act + integer(psb_ipk_) :: lx, ly + integer(psb_ipk_) :: ierr(5) + character(len=20) :: name, ch_err + + name='psb_geaxpby' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (m < 0) then + info = psb_err_iarg_neg_ + ierr(1) = 1; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + lx = size(x,1) + ly = size(y,1) + if (lx < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 3; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + if (ly < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 5; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + + if (m>0) call i2axpby(m,ione,alpha,x,lx,beta,y,ly,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psi_i2axpbyv + +subroutine psi_i2axpbyv2(m,alpha, x, beta, y, z, info) + + use psb_const_mod + use psb_error_mod + implicit none + integer(psb_ipk_), intent(in) :: m + integer(psb_i2pk_), intent (in) :: x(:) + integer(psb_i2pk_), intent (in) :: y(:) + integer(psb_i2pk_), intent (inout) :: z(:) + integer(psb_i2pk_), intent (in) :: alpha, beta + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_) :: err_act + integer(psb_ipk_) :: lx, ly, lz + integer(psb_ipk_) :: ierr(5) + character(len=20) :: name, ch_err + + name='psb_geaxpby' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (m < 0) then + info = psb_err_iarg_neg_ + ierr(1) = 1; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + lx = size(x,1) + ly = size(y,1) + lz = size(z,1) + if (lx < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 3; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + if (ly < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 5; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + if (lz < m) then + info = psb_err_input_asize_small_i_ + ierr(1) = 5; ierr(2) = m + call psb_errpush(info,name,i_err=ierr) + goto 9999 + end if + + if (m>0) call i2axpbyv2(m,ione,alpha,x,lx,beta,y,ly,z,lz,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(err_act) + + return + +end subroutine psi_i2axpbyv2 + +subroutine psi_i2gthmv(n,k,idx,alpha,x,beta,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:),alpha,beta + + ! Locals + integer(psb_ipk_) :: i, j, pt + + if (beta == i2zero) then + if (alpha == i2zero) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = i2zero + end do + end do + else if (alpha == i2one) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = x(idx(i),j) + end do + end do + else if (alpha == -i2one) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = -x(idx(i),j) + end do + end do + else + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = alpha*x(idx(i),j) + end do + end do + end if + else + if (beta == i2one) then + ! Do nothing + else if (beta == -i2one) then + y(1:n*k) = -y(1:n*k) + else + y(1:n*k) = beta*y(1:n*k) + end if + + if (alpha == i2zero) then + ! do nothing + else if (alpha == i2one) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = y(pt) + x(idx(i),j) + end do + end do + else if (alpha == -i2one) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = y(pt) - x(idx(i),j) + end do + end do + else + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt) = y(pt) + alpha*x(idx(i),j) + end do + end do + end if + end if + +end subroutine psi_i2gthmv + +subroutine psi_i2gthv(n,idx,alpha,x,beta,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: x(:), y(:),alpha,beta + + ! Locals + integer(psb_ipk_) :: i + if (beta == i2zero) then + if (alpha == i2zero) then + do i=1,n + y(i) = i2zero + end do + else if (alpha == i2one) then + do i=1,n + y(i) = x(idx(i)) + end do + else if (alpha == -i2one) then + do i=1,n + y(i) = -x(idx(i)) + end do + else + do i=1,n + y(i) = alpha*x(idx(i)) + end do + end if + else + if (beta == i2one) then + ! Do nothing + else if (beta == -i2one) then + y(1:n) = -y(1:n) + else + y(1:n) = beta*y(1:n) + end if + + if (alpha == i2zero) then + ! do nothing + else if (alpha == i2one) then + do i=1,n + y(i) = y(i) + x(idx(i)) + end do + else if (alpha == -i2one) then + do i=1,n + y(i) = y(i) - x(idx(i)) + end do + else + do i=1,n + y(i) = y(i) + alpha*x(idx(i)) + end do + end if + end if + +end subroutine psi_i2gthv + +subroutine psi_i2gthzmm(n,k,idx,x,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:,:) + + ! Locals + integer(psb_ipk_) :: i + + + do i=1,n + y(i,1:k)=x(idx(i),1:k) + end do + +end subroutine psi_i2gthzmm + +subroutine psi_i2gthzmv(n,k,idx,x,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: x(:,:), y(:) + + ! Locals + integer(psb_ipk_) :: i, j, pt + + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(pt)=x(idx(i),j) + end do + end do + +end subroutine psi_i2gthzmv + +subroutine psi_i2gthzv(n,idx,x,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: x(:), y(:) + + ! Locals + integer(psb_ipk_) :: i + + do i=1,n + y(i)=x(idx(i)) + end do + +end subroutine psi_i2gthzv + +subroutine psi_i2sctmm(n,k,idx,x,beta,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: beta, x(:,:), y(:,:) + + ! Locals + integer(psb_ipk_) :: i, j + + if (beta == i2zero) then + do i=1,n + y(idx(i),1:k) = x(i,1:k) + end do + else if (beta == i2one) then + do i=1,n + y(idx(i),1:k) = y(idx(i),1:k)+x(i,1:k) + end do + else + do i=1,n + y(idx(i),1:k) = beta*y(idx(i),1:k)+x(i,1:k) + end do + end if +end subroutine psi_i2sctmm + +subroutine psi_i2sctmv(n,k,idx,x,beta,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, k, idx(:) + integer(psb_i2pk_) :: beta, x(:), y(:,:) + + ! Locals + integer(psb_ipk_) :: i, j, pt + + if (beta == i2zero) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(idx(i),j) = x(pt) + end do + end do + else if (beta == i2one) then + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(idx(i),j) = y(idx(i),j)+x(pt) + end do + end do + else + pt=0 + do j=1,k + do i=1,n + pt=pt+1 + y(idx(i),j) = beta*y(idx(i),j)+x(pt) + end do + end do + end if +end subroutine psi_i2sctmv + +subroutine psi_i2sctv(n,idx,x,beta,y) + + use psb_const_mod + implicit none + + integer(psb_ipk_) :: n, idx(:) + integer(psb_i2pk_) :: beta, x(:), y(:) + + ! Locals + integer(psb_ipk_) :: i + + if (beta == i2zero) then + do i=1,n + y(idx(i)) = x(i) + end do + else if (beta == i2one) then + do i=1,n + y(idx(i)) = y(idx(i))+x(i) + end do + else + do i=1,n + y(idx(i)) = beta*y(idx(i))+x(i) + end do + end if +end subroutine psi_i2sctv + +subroutine i2axpby(m, n, alpha, X, lldx, beta, Y, lldy, info) + use psb_const_mod + use psb_error_mod + implicit none + integer(psb_ipk_) :: n, m, lldx, lldy, info + integer(psb_i2pk_) X(lldx,*), Y(lldy,*) + integer(psb_i2pk_) alpha, beta + integer(psb_ipk_) :: i, j + integer(psb_ipk_) :: int_err(5) + character name*20 + name='i2axpby' + + + ! + ! Error handling + ! + info = psb_success_ + if (m.lt.0) then + info=psb_err_iarg_neg_ + int_err(1)=1 + int_err(2)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (n.lt.0) then + info=psb_err_iarg_neg_ + int_err(1)=1 + int_err(2)=n + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (lldx.lt.max(1,m)) then + info=psb_err_iarg_not_gtia_ii_ + int_err(1)=5 + int_err(2)=1 + int_err(3)=lldx + int_err(4)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (lldy.lt.max(1,m)) then + info=psb_err_iarg_not_gtia_ii_ + int_err(1)=8 + int_err(2)=1 + int_err(3)=lldy + int_err(4)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + endif + + if (alpha.eq.i2zero) then + if (beta.eq.i2zero) then + do j=1, n + do i=1,m + y(i,j) = i2zero + enddo + enddo + else if (beta.eq.i2one) then + ! + ! Do nothing! + ! + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + y(i,j) = - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + y(i,j) = beta*y(i,j) + enddo + enddo + endif + + else if (alpha.eq.i2one) then + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + y(i,j) = x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + y(i,j) = x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + y(i,j) = x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + y(i,j) = x(i,j) + beta*y(i,j) + enddo + enddo + endif + + else if (alpha.eq.-i2one) then + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + y(i,j) = -x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + y(i,j) = -x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + y(i,j) = -x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + y(i,j) = -x(i,j) + beta*y(i,j) + enddo + enddo + endif + + else + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + y(i,j) = alpha*x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + y(i,j) = alpha*x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + y(i,j) = alpha*x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + y(i,j) = alpha*x(i,j) + beta*y(i,j) + enddo + enddo + endif + + endif + + return + +9999 continue + call fcpsb_serror() + return + +end subroutine i2axpby + +subroutine i2axpbyv2(m, n, alpha, X, lldx, beta, Y, lldy, Z, lldz, info) + use psb_const_mod + use psb_error_mod + implicit none + integer(psb_ipk_) :: n, m, lldx, lldy, lldz, info + integer(psb_i2pk_) X(lldx,*), Y(lldy,*), Z(lldy,*) + integer(psb_i2pk_) alpha, beta + integer(psb_ipk_) :: i, j + integer(psb_ipk_) :: int_err(5) + character name*20 + name='i2axpby' + + + ! + ! Error handling + ! + info = psb_success_ + if (m.lt.0) then + info=psb_err_iarg_neg_ + int_err(1)=1 + int_err(2)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (n.lt.0) then + info=psb_err_iarg_neg_ + int_err(1)=1 + int_err(2)=n + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (lldx.lt.max(1,m)) then + info=psb_err_iarg_not_gtia_ii_ + int_err(1)=5 + int_err(2)=1 + int_err(3)=lldx + int_err(4)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (lldy.lt.max(1,m)) then + info=psb_err_iarg_not_gtia_ii_ + int_err(1)=8 + int_err(2)=1 + int_err(3)=lldy + int_err(4)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + else if (lldz.lt.max(1,m)) then + info=psb_err_iarg_not_gtia_ii_ + int_err(1)=8 + int_err(2)=1 + int_err(3)=lldz + int_err(4)=m + call fcpsb_errpush(info,name,int_err) + goto 9999 + endif + + if (alpha.eq.i2zero) then + if (beta.eq.i2zero) then + do j=1, n + do i=1,m + Z(i,j) = i2zero + enddo + enddo + else if (beta.eq.i2one) then + ! + ! Do nothing! + ! + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + Z(i,j) = - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + Z(i,j) = beta*y(i,j) + enddo + enddo + endif + + else if (alpha.eq.i2one) then + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + Z(i,j) = x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + Z(i,j) = x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + Z(i,j) = x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + Z(i,j) = x(i,j) + beta*y(i,j) + enddo + enddo + endif + + else if (alpha.eq.-i2one) then + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + Z(i,j) = -x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + Z(i,j) = -x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + Z(i,j) = -x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + Z(i,j) = -x(i,j) + beta*y(i,j) + enddo + enddo + endif + + else + + if (beta.eq.i2zero) then + do j=1,n + do i=1,m + Z(i,j) = alpha*x(i,j) + enddo + enddo + else if (beta.eq.i2one) then + do j=1,n + do i=1,m + Z(i,j) = alpha*x(i,j) + y(i,j) + enddo + enddo + + else if (beta.eq.-i2one) then + do j=1,n + do i=1,m + Z(i,j) = alpha*x(i,j) - y(i,j) + enddo + enddo + else + do j=1,n + do i=1,m + Z(i,j) = alpha*x(i,j) + beta*y(i,j) + enddo + enddo + endif + + endif + + return + +9999 continue + call fcpsb_serror() + return + +end subroutine i2axpbyv2 diff --git a/base/tools/Makefile b/base/tools/Makefile index c29bee88f..6b103d410 100644 --- a/base/tools/Makefile +++ b/base/tools/Makefile @@ -25,7 +25,8 @@ FOBJS = psb_cdall.o psb_cdals.o psb_cdalv.o psb_cd_inloc.o psb_cdins.o psb_cdprt psb_cspalloc.o psb_cspasb.o psb_cspfree.o\ psb_cspins.o psb_csprn.o psb_cd_set_bld.o \ psb_s_map.o psb_d_map.o psb_c_map.o psb_z_map.o \ - psb_s_par_csr_spspmm.o psb_d_par_csr_spspmm.o psb_c_par_csr_spspmm.o psb_z_par_csr_spspmm.o + psb_s_par_csr_spspmm.o psb_d_par_csr_spspmm.o psb_c_par_csr_spspmm.o psb_z_par_csr_spspmm.o \ + psb_s_glob_transpose.o psb_d_glob_transpose.o psb_c_glob_transpose.o psb_z_glob_transpose.o # psb_lallc.o psb_lasb.o psb_lfree.o psb_lins.o \ MPFOBJS = psb_icdasb.o psb_ssphalo.o psb_dsphalo.o psb_csphalo.o psb_zsphalo.o \ diff --git a/base/tools/psb_c_glob_transpose.F90 b/base/tools/psb_c_glob_transpose.F90 new file mode 100644 index 000000000..a13da65a2 --- /dev/null +++ b/base/tools/psb_c_glob_transpose.F90 @@ -0,0 +1,902 @@ +! +! 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. +! +! +! File: psb_c_glob_transpose.f90 +! +! Subroutine: psb_c_glob_transpose +! Version: complex +! +! This file provides multiple related versions of a parallel +! global transpose +! +! B = A^T +! +! There are some variations of this routine, that are accounted for +! in the workhorse psb_lc_coo_glob_transpose +! 1. The row and column spaces can share the same descriptor +! This essentially means that the descriptor relates to a +! matrix with a symmetric pattern. Examples are: symmetric +! matrices, matrices with symmetric pattern, lower or +! upper halves of such matrices +! 2. The row and column index spaces are different +! In this case you need to have two descriptor on input, +! plus if you want the output to be distributed according +! to the row descriptor, you will still need a new descriptor +! because even if the row distribution is the same, the pattern +! will be different. +! +! This is handled in the workhorse by having one mandatory and +! two optional descriptors: +! 1. If only the mandatory descriptor is present, then it is assumed that it +! is both row and column descriptor, and that it is sufficient. +! 2. If two descriptors are available, then use the second +! 3. If the third output descriptor is available, then rebuild it +! after the data exchange. +! +! The main transpose algorithm works like this: +! 1. Compute sizes: any entry A(I,J) with J in the halo will have +! to be sent to the process owning J, so walk through the +! matrix and compute all the send sizes, then do an alltoall to figure +! the receive sizes; +! 2. Adjust send bufffers; +! 3. Perform a local transpose; +! 4. Split the matrix: all local entries stay, all halo entries go into +! the send buffers, and are converted to global numbering; +! 5. Do the all-to-all (see below for a discussion of the alternative +! communication strategies) +! 6. The receive is in the extra section of the ACOO buffer; convert +! the row indices to local numbering, and discard extra ones (there will +! be some) +! 7. If desc_rx was requested, make sure to insert the (new) column indices +! 8. Cleanup and sort the output matrix +! 9. Copy back into AIN or ATRANS if requested. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. +! +! +subroutine psb_lc_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_lc_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_lc_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_lc_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_lpk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzt, nzd + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:) + complex(psb_spk_), allocatable :: valsnd(:) + type(psb_lc_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),acoo%ia(nzl+1:nzl+iszr),& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(acoo%ja(nzl+1:nzl+nzt),info) + call psb_cdasb(desc_rx,info) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(acoo%ja(nzl+1:nzl+iszr),desc_r,info,iact='I') + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_lc_coo_glob_transpose + +subroutine psb_c_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_c_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_c_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_c_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_ipk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzd + integer(psb_lpk_) :: nzt, lszr + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:),iarcv(:),jarcv(:) + complex(psb_spk_), allocatable :: valsnd(:) + type(psb_c_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),iarcv,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),jarcv,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),iarcv(1:iszr),& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv(1:iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & iarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(jarcv(1:nzt),info) + call psb_cdasb(desc_rx,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(jarcv(1:iszr),desc_r,info,iact='I') + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,& + & iarcv,jarcv,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_c_coo_glob_transpose + +subroutine psb_c_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_c_simple_glob_transpose_ip + implicit none + type(psb_cspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_c_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lcspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ') + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_c_simple_glob_transpose_ip + +subroutine psb_c_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_c_simple_glob_transpose + implicit none + type(psb_cspmat_type), intent(in) :: ain + type(psb_cspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_c_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lcspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ') + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_c_simple_glob_transpose + +subroutine psb_lc_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_lc_simple_glob_transpose_ip + implicit none + type(psb_lcspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_lc_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lcspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_lc_simple_glob_transpose_ip + +subroutine psb_lc_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_lc_simple_glob_transpose + implicit none + type(psb_lcspmat_type), intent(in) :: ain + type(psb_lcspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_lc_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lcspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_lc_simple_glob_transpose + + diff --git a/base/tools/psb_c_par_csr_spspmm.f90 b/base/tools/psb_c_par_csr_spspmm.f90 index d835e27d2..058d1a627 100644 --- a/base/tools/psb_c_par_csr_spspmm.f90 +++ b/base/tools/psb_c_par_csr_spspmm.f90 @@ -39,7 +39,7 @@ ! C = A * B ! ! where all the matrices are stored in CSR. On input and output the matrices -! are stored with column indices in local numbering, but inermediate quantities +! are stored with column indices in local numbering, but intermediate quantities ! are in global numbering because gathering the halo of B to multiply it ! by A implies a potential enlargement of the support. ! Also, B may have a column index space different from its row index space, @@ -61,98 +61,100 @@ ! info - integer, output. ! Error code. ! -!!$Subroutine psb_c_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) -!!$ use psb_base_mod, psb_protect_name => psb_c_par_csr_spspmm -!!$ Implicit None -!!$ -!!$ type(psb_c_csr_sparse_mat),intent(in) :: acsr -!!$ type(psb_c_csr_sparse_mat),intent(inout) :: bcsr -!!$ type(psb_c_csr_sparse_mat),intent(out) :: ccsr -!!$ type(psb_desc_type),intent(in) :: desc_a -!!$ type(psb_desc_type),intent(inout) :: desc_c -!!$ integer(psb_ipk_), intent(out) :: info -!!$ integer(psb_ipk_), intent(in), optional :: data -!!$ ! ...local scalars.... -!!$ integer(psb_ipk_) :: ictxt, np,me -!!$ integer(psb_ipk_) :: ncol, nnz -!!$ type(psb_c_csr_sparse_mat) :: tcsr1 -!!$ logical :: update_desc_c -!!$ integer(psb_ipk_) :: debug_level, debug_unit, err_act -!!$ character(len=20) :: name, ch_err -!!$ -!!$ if(psb_get_errstatus() /= 0) return -!!$ info=psb_success_ -!!$ name='psb_c_p_csr_spspmm' -!!$ call psb_erractionsave(err_act) -!!$ if (psb_errstatus_fatal()) then -!!$ info = psb_err_internal_error_ ; goto 9999 -!!$ end if -!!$ debug_unit = psb_get_debug_unit() -!!$ debug_level = psb_get_debug_level() -!!$ -!!$ ictxt = desc_a%get_context() -!!$ -!!$ call psb_info(ictxt, me, np) -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),': Start' -!!$ -!!$ update_desc_c = desc_c%is_bld() -!!$ -!!$ ! -!!$ ! This is a bit tricky. -!!$ ! DESC_A is the descriptor of (the columns of) A, and therefore -!!$ ! of the rows of B; the columns of B, in the intended usage, span -!!$ ! a different space for which we have DESC_C. -!!$ ! We are gathering the halo rows of B to multiply by A; -!!$ ! now, the columns of B would ideally be kept in -!!$ ! global numbering, so that we can call this repeatedly to accumulate -!!$ ! the product of multiple operators, and convert to local numbering -!!$ ! at the last possible moment. However, this would imply calling -!!$ ! the serial SPSPMM with a matrix B with the GLOBAL number of columns -!!$ ! and this could be very expensive in memory. The solution is to keep B -!!$ ! in local numbering, so that only columns really appearing count, but to -!!$ ! expand the descriptor when gathering the halo, because by performing -!!$ ! the products we are extending the support of the operator; hence -!!$ ! this routine is intended to be called with a temporary descriptor -!!$ ! DESC_C which is in the BUILD state, to allow for such expansion -!!$ ! across multiple products. -!!$ ! The caller will at some later point finalize the descriptor DESC_C. -!!$ ! -!!$ -!!$ ncol = desc_a%get_local_cols() -!!$ call psb_sphalo(bcsr,desc_a,tcsr1,info,& -!!$ & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) -!!$ nnz = tcsr1%get_nzeros() -!!$ if (update_desc_c) then -!!$ call desc_c%indxmap%g2lip_ins(tcsr1%ja(1:nnz),info) -!!$ else -!!$ call desc_c%indxmap%g2lip(tcsr1%ja(1:nnz),info) -!!$ end if -!!$ if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr1) -!!$ if (info == psb_success_) call tcsr1%free() -!!$ if(info /= psb_success_) then -!!$ call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') -!!$ goto 9999 -!!$ end if -!!$ call bcsr%set_ncols(desc_c%get_local_cols()) -!!$ -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm 3' -!!$ if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() -!!$ call psb_spspmm(acsr,bcsr,ccsr,info) -!!$ -!!$ call psb_erractionrestore(err_act) -!!$ return -!!$ -!!$9999 call psb_error_handler(ictxt,err_act) -!!$ -!!$ return -!!$ -!!$End Subroutine psb_c_par_csr_spspmm +Subroutine psb_c_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + use psb_base_mod, psb_protect_name => psb_c_par_csr_spspmm + Implicit None + + type(psb_c_csr_sparse_mat),intent(in) :: acsr + type(psb_c_csr_sparse_mat),intent(inout) :: bcsr + type(psb_c_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: ncol, nnz + type(psb_lc_csr_sparse_mat) :: ltcsr + type(psb_c_csr_sparse_mat) :: tcsr + logical :: update_desc_c + integer(psb_ipk_) :: debug_level, debug_unit, err_act + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='psb_c_p_csr_spspmm' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_a%get_context() + + call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + update_desc_c = desc_c%is_bld() + + ! + ! This is a bit tricky. + ! DESC_A is the descriptor of (the columns of) A, and therefore + ! of the rows of B; the columns of B, in the intended usage, span + ! a different space for which we have DESC_C. + ! We are gathering the halo rows of B to multiply by A; + ! now, the columns of B would ideally be kept in + ! global numbering, so that we can call this repeatedly to accumulate + ! the product of multiple operators, and convert to local numbering + ! at the last possible moment. However, this would imply calling + ! the serial SPSPMM with a matrix B with the GLOBAL number of columns + ! and this could be very expensive in memory. The solution is to keep B + ! in local numbering, so that only columns really appearing count, but to + ! expand the descriptor when gathering the halo, because by performing + ! the products we are extending the support of the operator; hence + ! this routine is intended to be called with a temporary descriptor + ! DESC_C which is in the BUILD state, to allow for such expansion + ! across multiple products. + ! The caller will at some later point finalize the descriptor DESC_C. + ! + + ncol = desc_a%get_local_cols() + call psb_sphalo(bcsr,desc_a,ltcsr,info,& + & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) + nnz = ltcsr%get_nzeros() + if (update_desc_c) then + call desc_c%indxmap%g2lip_ins(ltcsr%ja(1:nnz),info) + else + call desc_c%indxmap%g2lip(ltcsr%ja(1:nnz),info) + end if + call ltcsr%mv_to_ifmt(tcsr,info) + if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr) + if (info == psb_success_) call tcsr%free() + if(info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') + goto 9999 + end if + call bcsr%set_ncols(desc_c%get_local_cols()) + + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm 3' + if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() + call psb_spspmm(acsr,bcsr,ccsr,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +End Subroutine psb_c_par_csr_spspmm Subroutine psb_lc_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) use psb_base_mod, psb_protect_name => psb_lc_par_csr_spspmm diff --git a/base/tools/psb_cd_inloc.f90 b/base/tools/psb_cd_inloc.f90 index 1cb2c9137..010901b59 100644 --- a/base/tools/psb_cd_inloc.f90 +++ b/base/tools/psb_cd_inloc.f90 @@ -67,8 +67,8 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) & nov(:), ov_idx(:,:), temp_ovrlap(:) integer(psb_lpk_), allocatable :: vl(:), ix(:), l_temp_ovrlap(:) integer(psb_ipk_) :: debug_level, debug_unit - integer(psb_mpk_) :: iictxt - real(psb_dpk_) :: t0, t1, t2, t3, t4, t5 + real(psb_dpk_) :: t0, t1, t2, t3, t4, t5 + logical, parameter :: debug_size=.false. logical :: do_timings=.false. logical :: check_, islarge, usehash_ character(len=20) :: name @@ -84,14 +84,13 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) call psb_info(ictxt, me, np) if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': start',np - iictxt = ictxt if (do_timings) then call psb_barrier(ictxt) t0 = psb_wtime() end if loc_row = size(v) - m = maxval(v) - nrt = loc_row + m = maxval(v) + nrt = loc_row call psb_sum(ictxt,nrt) call psb_max(ictxt,m) @@ -148,12 +147,14 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) islarge = psb_cd_is_large_size(m) - allocate(vl(loc_row),ix(loc_row),stat=info) + allocate(vl(max(loc_row,ione)),ix(max(loc_row,ione)),stat=info) if (info /= psb_success_) then info=psb_err_alloc_dealloc_ call psb_errpush(info,name,l_err=l_err) goto 9999 end if + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': sizes',loc_row,m,nrt,check_ ! ! Checks for valid input: @@ -164,6 +165,9 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) ! if (check_.or.(.not.islarge)) then + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Going for global checks' + allocate(tmpgidx(m,2),stat=info) if (info /= psb_success_) then info=psb_err_alloc_dealloc_ @@ -228,6 +232,9 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) write(psb_err_unit,*) trim(name),' : in the global sizes!',m,nrt end if end if + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': After global checks ' + if (do_timings) then call psb_barrier(ictxt) t1 = psb_wtime() @@ -254,7 +261,7 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) end do end if call psb_msort(vl,ix,flag=psb_sort_keep_idx_) - nlu = 1 + nlu = min(1,loc_row) do i=2,loc_row if (vl(i) /= vl(nlu)) then nlu = nlu + 1 @@ -264,6 +271,9 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) end do call psb_msort(ix(1:nlu),vl(1:nlu),flag=psb_sort_keep_idx_) + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': After sort ',nlu + call psb_nullify_desc(desc) if (do_timings) then call psb_barrier(ictxt) @@ -276,7 +286,10 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) ! then novrl = 0, hence all accesses to tmpgidx ! are safe. ! - if (novrl > 0) then + if (novrl > 0) then + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Check overlap ' + if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': code for NOVRL>0',novrl,npr_ov @@ -320,6 +333,9 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) call psb_msort(ov_idx(:,1),ix=ov_idx(:,2),flag=psb_sort_keep_idx_) end if + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Done overlap ' + ! allocate work vector allocate(l_temp_ovrlap(max(1,2*loc_row)),desc%lprm(1),& @@ -375,7 +391,9 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) call psb_barrier(ictxt) t3 = psb_wtime() end if - + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Allocate indxmap' + if (np == 1) then allocate(psb_repl_map :: desc%indxmap, stat=info) else @@ -388,11 +406,15 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) select type(aa => desc%indxmap) type is (psb_repl_map) - call aa%repl_map_init(iictxt,m,info) + call aa%repl_map_init(ictxt,m,info) class default - call aa%init(iictxt,vl(1:nlu),info) + call aa%init(ictxt,vl(1:nlu),info) end select + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Done init indxmap' + + if (do_timings) then call psb_barrier(ictxt) t4 = psb_wtime() @@ -420,6 +442,8 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) end if end block if (info == psb_success_) call psi_bld_tmpovrl(temp_ovrlap,desc,info) + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Done bld_tmpovrl' if (info == psb_success_) deallocate(temp_ovrlap,vl,ix,stat=info) if ((info == psb_success_).and.(allocated(tmpgidx)))& @@ -455,6 +479,8 @@ subroutine psb_cd_inloc(v, ictxt, desc, info, globalcheck,idx,usehash) write(0,*) ' Phase 5 : ', t5 end if end if + if (debug_size) & + & write(debug_unit,*) me,' ',trim(name),': Done cd_inloc' call psb_erractionrestore(err_act) return diff --git a/base/tools/psb_cd_reinit.f90 b/base/tools/psb_cd_reinit.f90 index d579ba95e..15dbbc590 100644 --- a/base/tools/psb_cd_reinit.f90 +++ b/base/tools/psb_cd_reinit.f90 @@ -69,6 +69,9 @@ Subroutine psb_cd_reinit(desc,info) call psb_move_alloc(tmp_halo,desc%halo_index,info) call psb_move_alloc(tmp_ext,desc%ext_index,info) call desc%indxmap%reinit(info) +!!$ if (me == 0) write(0,*) 'On cdreinit status :',& +!!$ & allocated(desc%indxmap%p_adjcncy),allocated(desc%indxmap%halo_owner), & +!!$ & desc%get_fmt() ! call psb_cd_set_bld(desc,info) end if diff --git a/base/tools/psb_cd_renum_block.F90 b/base/tools/psb_cd_renum_block.F90 index 531d14dfb..1d64a09e0 100644 --- a/base/tools/psb_cd_renum_block.F90 +++ b/base/tools/psb_cd_renum_block.F90 @@ -53,9 +53,9 @@ subroutine psb_cd_renum_block(desc_in, desc_out, info) type(psb_gen_block_map), allocatable :: blck_map integer(psb_ipk_), allocatable :: lidx(:),reflidx(:) integer(psb_lpk_), allocatable :: gidx(:),vnl(:) - integer(psb_ipk_) :: i,n_row, n_col - integer(psb_lpk_) :: li,n_glob_row, n_glob_col - integer(psb_ipk_) :: np,me,ictxt, err_act + integer(psb_ipk_) :: i, n_row, n_col + integer(psb_lpk_) :: li, n_glob_row, n_glob_col + integer(psb_ipk_) :: np, me, ictxt, err_act integer(psb_ipk_) :: debug_level, debug_unit character(len=20) :: name diff --git a/base/tools/psb_cd_switch_ovl_indxmap.f90 b/base/tools/psb_cd_switch_ovl_indxmap.f90 index ea8aabcfc..b2bdd9e42 100644 --- a/base/tools/psb_cd_switch_ovl_indxmap.f90 +++ b/base/tools/psb_cd_switch_ovl_indxmap.f90 @@ -51,7 +51,6 @@ Subroutine psb_cd_switch_ovl_indxmap(desc,info) integer(psb_lpk_), allocatable :: vl(:) integer(psb_ipk_) :: debug_level, debug_unit, ierr(5) - integer(psb_mpk_) :: iictxt character(len=20) :: name, ch_err name='cd_switch_ovl_indxmap' @@ -66,7 +65,6 @@ Subroutine psb_cd_switch_ovl_indxmap(desc,info) If (debug_level >= psb_debug_outer_) & & Write(debug_unit,*) me,' ',trim(name),& & ': start' - iictxt = ictxt mglob = desc%get_global_rows() n_row = desc%get_local_rows() n_col = desc%get_local_cols() @@ -99,7 +97,7 @@ Subroutine psb_cd_switch_ovl_indxmap(desc,info) end if if (info == psb_success_)& - & call desc%indxmap%init(iictxt,vl(1:n_row),info) + & call desc%indxmap%init(ictxt,vl(1:n_row),info) if (info == psb_success_) call psb_cd_set_bld(desc,info) if (info == psb_success_) & & call desc%indxmap%g2lip_ins(vl(n_row+1:n_col),info) diff --git a/base/tools/psb_cdall.f90 b/base/tools/psb_cdall.f90 index 0f0ec813a..15ce572fd 100644 --- a/base/tools/psb_cdall.f90 +++ b/base/tools/psb_cdall.f90 @@ -57,7 +57,6 @@ subroutine psb_cdall(ictxt, desc, info,mg,ng,parts,vg,vl,flag,nl,repl,globalchec logical :: usehash_ integer(psb_ipk_), allocatable :: itmpv(:) integer(psb_lpk_), allocatable :: lvl(:) - integer(psb_mpk_) :: iictxt @@ -67,7 +66,6 @@ subroutine psb_cdall(ictxt, desc, info,mg,ng,parts,vg,vl,flag,nl,repl,globalchec call psb_erractionsave(err_act) call psb_info(ictxt, me, np) - iictxt = ictxt if (count((/ present(vg),present(vl),& & present(parts),present(nl), present(repl) /)) /= 1) then info=psb_err_no_optional_arg_ @@ -159,9 +157,9 @@ subroutine psb_cdall(ictxt, desc, info,mg,ng,parts,vg,vl,flag,nl,repl,globalchec select type(aa => desc%indxmap) type is (psb_repl_map) n_ = nl - call aa%repl_map_init(iictxt,n_,info) + call aa%repl_map_init(ictxt,n_,info) type is (psb_gen_block_map) - call aa%gen_block_map_init(iictxt,nl,info) + call aa%gen_block_map_init(ictxt,nl,info) class default ! This cannot happen info = psb_err_internal_error_ diff --git a/base/tools/psb_cdals.f90 b/base/tools/psb_cdals.f90 index dc8a28738..dfee41135 100644 --- a/base/tools/psb_cdals.f90 +++ b/base/tools/psb_cdals.f90 @@ -67,7 +67,6 @@ subroutine psb_cdals(m, n, parts, ictxt, desc, info) integer(psb_ipk_), allocatable :: prc_v(:) integer(psb_ipk_) :: debug_level, debug_unit integer(psb_ipk_) :: me, np, nprocs - integer(psb_mpk_) :: iictxt character(len=20) :: name if(psb_get_errstatus() /= 0) return @@ -239,12 +238,11 @@ subroutine psb_cdals(m, n, parts, ictxt, desc, info) if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': End main loop:' ,loc_row,itmpov,info - iictxt = ictxt select type(aa => desc%indxmap) type is (psb_repl_map) - call aa%repl_map_init(iictxt,m,info) + call aa%repl_map_init(ictxt,m,info) class default - call aa%init(iictxt,loc_idx(1:k),info) + call aa%init(ictxt,loc_idx(1:k),info) end select diff --git a/base/tools/psb_cdalv.f90 b/base/tools/psb_cdalv.f90 index 1e433eaae..8b850f6be 100644 --- a/base/tools/psb_cdalv.f90 +++ b/base/tools/psb_cdalv.f90 @@ -64,7 +64,6 @@ subroutine psb_cdalv(v, ictxt, desc, info, flag) integer(psb_lpk_) :: l_err(5) integer(psb_ipk_), allocatable :: temp_ovrlap(:) integer(psb_ipk_) :: debug_level, debug_unit - integer(psb_mpk_) :: iictxt character(len=20) :: name if(psb_get_errstatus() /= 0) return @@ -77,7 +76,6 @@ subroutine psb_cdalv(v, ictxt, desc, info, flag) call psb_info(ictxt, me, np) if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': ',np,me - iictxt = ictxt m = size(v) n = m !... check m and n parameters.... @@ -192,11 +190,11 @@ subroutine psb_cdalv(v, ictxt, desc, info, flag) select type(aa => desc%indxmap) type is (psb_repl_map) - call aa%repl_map_init(iictxt,m,info) + call aa%repl_map_init(ictxt,m,info) type is (psb_hash_map) - call aa%hash_map_init(iictxt,v,info) + call aa%hash_map_init(ictxt,v,info) type is (psb_glist_map) - call aa%glist_map_init(iictxt,v,info) + call aa%glist_map_init(ictxt,v,info) class default ! This cannot happen info = psb_err_internal_error_ diff --git a/base/tools/psb_cdins.f90 b/base/tools/psb_cdins.F90 similarity index 99% rename from base/tools/psb_cdins.f90 rename to base/tools/psb_cdins.F90 index 5e2192966..d1b186f94 100644 --- a/base/tools/psb_cdins.f90 +++ b/base/tools/psb_cdins.F90 @@ -45,6 +45,7 @@ ! ila(:) - integer(psb_ipk_), optional The row indices in local numbering ! jla(:) - integer(psb_ipk_), optional The col indices in local numbering ! +#if defined(IPK4) && defined(LPK8) subroutine psb_cdinsrc(nz,ia,ja,desc_a,info,ila,jla) use psb_base_mod, psb_protect_name => psb_cdinsrc use psi_mod @@ -61,7 +62,7 @@ subroutine psb_cdinsrc(nz,ia,ja,desc_a,info,ila,jla) lnz = nz call psb_cdins(lnz,ia,ja,desc_a,info,ila,jla) end subroutine psb_cdinsrc - +#endif subroutine psb_lcdinsrc(nz,ia,ja,desc_a,info,ila,jla) use psb_base_mod, psb_protect_name => psb_lcdinsrc use psi_mod @@ -180,6 +181,7 @@ end subroutine psb_lcdinsrc ! mask(:) - logical, optional, target ! lidx(:) - integer(psb_ipk_), optional User-defined local col indices ! +#if defined(IPK4) && defined(LPK8) subroutine psb_cdinsc(nz,ja,desc,info,jla,mask,lidx) use psb_base_mod, psb_protect_name => psb_cdinsc use psi_mod @@ -199,7 +201,7 @@ subroutine psb_cdinsc(nz,ja,desc,info,jla,mask,lidx) lnz = nz call psb_cdins(lnz,ja,desc,info,jla,mask,lidx) end subroutine psb_cdinsc - +#endif subroutine psb_lcdinsc(nz,ja,desc,info,jla,mask,lidx) use psb_base_mod, psb_protect_name => psb_lcdinsc use psi_mod diff --git a/base/tools/psb_cdrep.f90 b/base/tools/psb_cdrep.f90 index 61f0ac2ad..2ba47c2c9 100644 --- a/base/tools/psb_cdrep.f90 +++ b/base/tools/psb_cdrep.f90 @@ -118,7 +118,6 @@ subroutine psb_cdrep(m, ictxt, desc, info) integer(psb_lpk_) :: l_err(5),exch(2) integer(psb_ipk_) :: thalo(1), tovr(1), text(1) integer(psb_ipk_) :: debug_level, debug_unit - integer(psb_mpk_) :: iictxt character(len=20) :: name if(psb_get_errstatus() /= 0) return @@ -131,7 +130,6 @@ subroutine psb_cdrep(m, ictxt, desc, info) call psb_info(ictxt, me, np) if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': ',np - iictxt = ictxt n = m !... check m and n parameters.... if (m < 1) then @@ -182,7 +180,7 @@ subroutine psb_cdrep(m, ictxt, desc, info) allocate(psb_repl_map :: desc%indxmap, stat=info) select type(aa => desc%indxmap) type is (psb_repl_map) - call aa%repl_map_init(iictxt,m,info) + call aa%repl_map_init(ictxt,m,info) class default ! This cannot happen info = psb_err_internal_error_ diff --git a/base/tools/psb_cspasb.f90 b/base/tools/psb_cspasb.f90 index ae5c0af2c..073fcbbd8 100644 --- a/base/tools/psb_cspasb.f90 +++ b/base/tools/psb_cspasb.f90 @@ -122,11 +122,11 @@ subroutine psb_cspasb(a,desc_a, info, afmt, upd, dupl, mold) end if - IF (debug_level >= psb_debug_ext_) then + if (debug_level >= psb_debug_ext_) then ch_err=a%get_fmt() write(debug_unit, *) me,' ',trim(name),': From SPCNV',& & info,' ',ch_err - end IF + end if if (psb_errstatus_fatal()) then info=psb_err_from_subroutine_ diff --git a/base/tools/psb_csphalo.F90 b/base/tools/psb_csphalo.F90 index f0432cc64..668f7d522 100644 --- a/base/tools/psb_csphalo.F90 +++ b/base/tools/psb_csphalo.F90 @@ -31,11 +31,26 @@ ! ! File: psb_csphalo.f90 ! -! Subroutine: psb_csphalo +! Subroutine: psb_csphalo psb_lcsphalo ! This routine does the retrieval of remote matrix rows. -! Note that retrieval is done through GTBLK, therefore it should work -! for any matrix format in A; as for the output, default is CSR. -! +! Retrieval is done through GETROW, therefore it should work +! for any matrix format in A; as for the output, default is CSR. +! +! There is also a specialized version lc_CSR whose interface +! is adapted for the needs of c_par_csr_spspmm. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. ! ! Arguments: ! a - type(psb_cspmat_type) The local part of input matrix A @@ -55,9 +70,6 @@ ! psb_comm_ext_ use ext_index ! psb_comm_ovrl_ DISABLED for this routine. ! -#undef SP_A2AV_MPI -#undef SP_A2AV_XI -#define SP_A2AV_MAT Subroutine psb_csphalo(a,desc_a,blk,info,rowcnv,colcnv,& & rowscale,colscale,outfmt,data) use psb_base_mod, psb_protect_name => psb_csphalo @@ -314,16 +326,36 @@ Subroutine psb_csphalo(a,desc_a,blk,info,rowcnv,colcnv,& call psb_errpush(info,name,a_err=ch_err); goto 9999 end if - - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,iarcv,jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& & iarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -390,16 +422,36 @@ Subroutine psb_csphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -506,8 +558,7 @@ Subroutine psb_lcsphalo(a,desc_a,blk,info,rowcnv,colcnv,& integer(psb_ipk_), intent(in), optional :: data ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter, proc, i, & - & n_el_send,n_el_recv,& + integer(psb_ipk_) :: counter, proc, i, n_el_send,n_el_recv, & & n_elem, j, ipx,mat_recv, idxs,idxr,nz,& & data_,totxch,nxs, nxr, ncg integer(psb_lpk_) :: r, k, irmin, irmax, icmin, icmax, iszs, iszr, & @@ -718,16 +769,37 @@ Subroutine psb_lcsphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -829,12 +901,11 @@ Subroutine psb_lc_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& type(psb_desc_type),Intent(in), optional, target :: col_desc ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter,proc,i, & - & n_el_send,k,n_el_recv,r,& - & n_elem, j, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& - & irmin,icmin,data_,totxch,nxs, nxr,& - & err_act, nsnds, nrcvs - integer(psb_lpk_) :: ngtz,irmax,icmax,l1, lnr, lnc, lnnz, ncg, jpx, idx, tot_elem + integer(psb_ipk_) :: counter,proc,i, n_el_send,n_el_recv,& + & n_elem, j,ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & data_,totxch,nxs, nxr, err_act, nsnds, nrcvs + integer(psb_lpk_) :: ngtz,irmax,icmax,irmin,icmin,l1, lnr, lnc, lnnz, & + & r, k, ncg, jpx, idx, tot_elem integer(psb_mpk_) :: icomm, minfo integer(psb_mpk_), allocatable :: brvindx(:), & & rvsz(:), bsdindx(:),sdsz(:) @@ -1054,32 +1125,36 @@ Subroutine psb_lc_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if -#if defined(SP_A2AV_MPI) - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo /= mpi_success) info = minfo -#elif defined(SP_A2AV_XI) - call lc_my_a2av(valsnd,sdsz,bsdindx,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& & acoo%val,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(iasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& & acoo%ia,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(jasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& & acoo%ja,rvsz,brvindx,ictxt,info) -#elif defined(SP_A2AV_MAT) - call lc_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ipdxv,ictxt,icomm,info) -#else - choke on me @! -#endif + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -1163,185 +1238,376 @@ Subroutine psb_lc_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& return -#if defined(SP_A2AV_XI) || defined(SP_A2AV_MAT) -contains +End Subroutine psb_lc_csr_halo -#if defined(SP_A2AV_MAT) - subroutine lc_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & valrcv,iarcv,jarcv,rvsz,brvindx,ipdxv,ictxt,icomm,info) +Subroutine psb_c_lc_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + use psb_base_mod, psb_protect_name => psb_c_lc_csr_halo #ifdef MPI_MOD - use mpi + use mpi #endif - Implicit None + Implicit None #ifdef MPI_H - include 'mpif.h' + include 'mpif.h' #endif - complex(psb_spk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(in) :: ipdxv(:) - integer(psb_lpk_), intent(in) :: iasnd(:), jasnd(:) - complex(psb_spk_), intent(out) :: valrcv(:) - integer(psb_lpk_), intent(out) :: iarcv(:), jarcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_mpk_), intent(in) :: icomm - integer(psb_ipk_), intent(out) :: info - !Local variables - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter - integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret - integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(rowcnv)) then + rowcnv_ = rowcnv + else + rowcnv_ = .true. + endif + if (present(colcnv)) then + colcnv_ = colcnv + else + colcnv_ = .true. + endif + if (present(rowscale)) then + rowscale_ = rowscale + else + rowscale_ = .false. + endif + if (present(colscale)) then + colscale_ = colscale + else + colscale_ = .false. + endif + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + if (present(outcol_glob)) then + outcol_glob_ = outcol_glob + else + outcol_glob_ = .false. + endif + if (present(col_desc)) then + col_desc_ => col_desc + else + col_desc_ => desc_a + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + If (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Data selector',data_ + select case(data_) + case(psb_comm_halo_,psb_comm_ext_ ) + ! Do not accept OVRLAP_INDEX any longer. + case default + call psb_errpush(psb_err_from_subroutine_,name,a_err='wrong Data selector') + goto 9999 + end select - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - p2ptag = psb_complex_swap_tag - call mpi_irecv(valrcv(idx+1:idx+sz),sz,& - & psb_mpi_c_spk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,1),iret) - p2ptag = psb_int_swap_tag - call mpi_irecv(iarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,2),iret) - call mpi_irecv(jarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,3),iret) - end if - counter = counter+n_el_send+3 + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + call desc_a%get_list(data_,pdxv,totxch,nxr,nxs,info) + ipdxv = pdxv%get_vect() + ! For all rows in the halo descriptor, extract the row size + lnr = 0 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + tot_elem = 0 + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + tot_elem = tot_elem+n_elem Enddo + sdsz(proc+1) = tot_elem + lnr = lnr + n_el_recv + counter = counter+n_el_send+3 + Enddo + ! + ! Exchange row sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! size of the rows may vary, as opposed to fixed + ! (multi) vector row size. + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - p2ptag = psb_complex_swap_tag - call mpi_send(valsnd(idx+1:idx+sz),sz,& - & psb_mpi_c_spk_,prcid(ip+1),& - & p2ptag, icomm,iret) - p2ptag = psb_int_swap_tag - call mpi_send(iasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - call mpi_send(jasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) + idxs = 0 + idxr = 0 + counter = 1 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + counter = counter+n_el_send+3 + Enddo + + iszr = sum(rvsz) + mat_recv = iszr + iszs = sum(sdsz) + + lnnz = max(iszr,iszs,ione) + lnc = a%get_ncols() + call acoo%allocate(lnr,lnc,lnnz) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',acoo%get_size(),& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),liasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),ljasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + l1 = 0 + ipx = 1 + counter=1 + idx = 0 + ! + ! Make sure to get all columns in csget. + ! This is necessary when sphalo is used to compute a transpose, + ! as opposed to just gathering halo for spspmm purposes. + ! + ncg = huge(ncg) + tot_elem = 0 + Do + proc = ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + call a%csget(idx,idx,ngtz,iasnd,jasnd,valsnd,info,& + & append=.true.,nzin=tot_elem,jmax=ncg) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_sp_getrow') + goto 9999 end if - counter = counter+n_el_send+3 + tot_elem = tot_elem+ngtz Enddo + counter = counter+n_el_send+3 + Enddo + nz = tot_elem - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - sz = rvsz(ip+1) - if (sz > 0) then - call mpi_wait(rvhd(ip+1,1),p2pstat,iret) - call mpi_wait(rvhd(ip+1,2),p2pstat,iret) - call mpi_wait(rvhd(ip+1,3),p2pstat,iret) - end if - counter = counter+n_el_send+3 - Enddo + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Going for alltoallv',iszs,iszr + if (rowcnv_) then + call psb_loc_to_glob(iasnd(1:nz),liasnd(1:nz),desc_a,info,iact='I') + else + liasnd(1:nz) = iasnd(1:nz) + end if + if (colcnv_) then + call psb_loc_to_glob(jasnd(1:nz),ljasnd(1:nz),col_desc_,info,iact='I') + else + ljasnd(1:nz) = jasnd(1:nz) + end if + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_loc_to_glob') + goto 9999 + end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,liasnd,ljasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(liasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(ljasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(liasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(ljasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - end subroutine lc_coo_my_a2av -#endif -#if defined(SP_A2AV_XI) - subroutine lc_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - complex(psb_spk_), intent(in) :: valsnd(:) - complex(psb_spk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + ! + ! Convert into local numbering + ! + if (rowcnv_) call psb_glob_to_loc(acoo%ia(1:iszr),desc_a,info,iact='I') + ! + ! This seems to be the correct output condition + ! + if (colcnv_.and.(.not.outcol_glob_)) & + & call psb_glob_to_loc(acoo%ja(1:iszr),col_desc_,info,iact='I') - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psbglob_to_loc') + goto 9999 + end if - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))0).and.(k>0)) Then + l1=l1+1 + acoo%val(l1) = acoo%val(i) + acoo%ia(l1) = r + acoo%ja(l1) = k + irmin = min(irmin,r) + irmax = max(irmax,r) + icmin = min(icmin,k) + icmax = max(icmax,k) + End If + Enddo + if (rowscale_) then + call acoo%set_nrows(max(irmax-irmin+1,0)) + acoo%ia(1:l1) = acoo%ia(1:l1) - irmin + 1 + else + call acoo%set_nrows(irmax) + end if + if (colscale_) then + call acoo%set_ncols(max(icmax-icmin+1,0)) + acoo%ja(1:l1) = acoo%ja(1:l1) - icmin + 1 + else + call acoo%set_ncols(icmax) + end if - do ip = 0, np-1 - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do + call acoo%set_nzeros(l1) + call acoo%set_sorted(.false.) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine lc_my_a2av + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),& + & ': End data exchange',counter,l1 - subroutine i_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - integer(psb_ipk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info - + call acoo%fix(info) + if (info == psb_success_) call acoo%mv_to_fmt(blk,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_spcnv') + goto 9999 + end if - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do +9999 call psb_error_handler(ictxt,err_act) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine i_my_a2av -#endif -#endif -End Subroutine psb_lc_csr_halo + return + +End Subroutine psb_c_lc_csr_halo diff --git a/base/tools/psb_cspins.f90 b/base/tools/psb_cspins.F90 similarity index 99% rename from base/tools/psb_cspins.f90 rename to base/tools/psb_cspins.F90 index c17c14093..c2a52eb3c 100644 --- a/base/tools/psb_cspins.f90 +++ b/base/tools/psb_cspins.F90 @@ -288,6 +288,7 @@ subroutine psb_cspins_csr_lirp(nr,irp,ja,val,irw,a,desc_a,info,rebuild,local) end subroutine psb_cspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_cspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) use psb_base_mod, psb_protect_name => psb_cspins_csr_iirp use psi_mod @@ -384,6 +385,7 @@ subroutine psb_cspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) return end subroutine psb_cspins_csr_iirp +#endif subroutine psb_cspins_2desc(nz,ia,ja,val,a,desc_ar,desc_ac,info) use psb_base_mod, psb_protect_name => psb_cspins_2desc diff --git a/base/tools/psb_d_glob_transpose.F90 b/base/tools/psb_d_glob_transpose.F90 new file mode 100644 index 000000000..9f7692d6f --- /dev/null +++ b/base/tools/psb_d_glob_transpose.F90 @@ -0,0 +1,902 @@ +! +! 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. +! +! +! File: psb_d_glob_transpose.f90 +! +! Subroutine: psb_d_glob_transpose +! Version: real +! +! This file provides multiple related versions of a parallel +! global transpose +! +! B = A^T +! +! There are some variations of this routine, that are accounted for +! in the workhorse psb_ld_coo_glob_transpose +! 1. The row and column spaces can share the same descriptor +! This essentially means that the descriptor relates to a +! matrix with a symmetric pattern. Examples are: symmetric +! matrices, matrices with symmetric pattern, lower or +! upper halves of such matrices +! 2. The row and column index spaces are different +! In this case you need to have two descriptor on input, +! plus if you want the output to be distributed according +! to the row descriptor, you will still need a new descriptor +! because even if the row distribution is the same, the pattern +! will be different. +! +! This is handled in the workhorse by having one mandatory and +! two optional descriptors: +! 1. If only the mandatory descriptor is present, then it is assumed that it +! is both row and column descriptor, and that it is sufficient. +! 2. If two descriptors are available, then use the second +! 3. If the third output descriptor is available, then rebuild it +! after the data exchange. +! +! The main transpose algorithm works like this: +! 1. Compute sizes: any entry A(I,J) with J in the halo will have +! to be sent to the process owning J, so walk through the +! matrix and compute all the send sizes, then do an alltoall to figure +! the receive sizes; +! 2. Adjust send bufffers; +! 3. Perform a local transpose; +! 4. Split the matrix: all local entries stay, all halo entries go into +! the send buffers, and are converted to global numbering; +! 5. Do the all-to-all (see below for a discussion of the alternative +! communication strategies) +! 6. The receive is in the extra section of the ACOO buffer; convert +! the row indices to local numbering, and discard extra ones (there will +! be some) +! 7. If desc_rx was requested, make sure to insert the (new) column indices +! 8. Cleanup and sort the output matrix +! 9. Copy back into AIN or ATRANS if requested. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. +! +! +subroutine psb_ld_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_ld_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_ld_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_ld_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_lpk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzt, nzd + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:) + real(psb_dpk_), allocatable :: valsnd(:) + type(psb_ld_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),acoo%ia(nzl+1:nzl+iszr),& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(acoo%ja(nzl+1:nzl+nzt),info) + call psb_cdasb(desc_rx,info) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(acoo%ja(nzl+1:nzl+iszr),desc_r,info,iact='I') + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_ld_coo_glob_transpose + +subroutine psb_d_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_d_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_d_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_d_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_ipk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzd + integer(psb_lpk_) :: nzt, lszr + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:),iarcv(:),jarcv(:) + real(psb_dpk_), allocatable :: valsnd(:) + type(psb_d_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),iarcv,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),jarcv,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),iarcv(1:iszr),& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv(1:iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & iarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(jarcv(1:nzt),info) + call psb_cdasb(desc_rx,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(jarcv(1:iszr),desc_r,info,iact='I') + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,& + & iarcv,jarcv,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_d_coo_glob_transpose + +subroutine psb_d_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_d_simple_glob_transpose_ip + implicit none + type(psb_dspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_d_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_ldspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ') + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_d_simple_glob_transpose_ip + +subroutine psb_d_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_d_simple_glob_transpose + implicit none + type(psb_dspmat_type), intent(in) :: ain + type(psb_dspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_d_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_ldspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ') + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_d_simple_glob_transpose + +subroutine psb_ld_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_ld_simple_glob_transpose_ip + implicit none + type(psb_ldspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_ld_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_ldspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_ld_simple_glob_transpose_ip + +subroutine psb_ld_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_ld_simple_glob_transpose + implicit none + type(psb_ldspmat_type), intent(in) :: ain + type(psb_ldspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_ld_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_ldspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_ld_simple_glob_transpose + + diff --git a/base/tools/psb_d_par_csr_spspmm.f90 b/base/tools/psb_d_par_csr_spspmm.f90 index 7edfbac8b..2e34a32c5 100644 --- a/base/tools/psb_d_par_csr_spspmm.f90 +++ b/base/tools/psb_d_par_csr_spspmm.f90 @@ -39,7 +39,7 @@ ! C = A * B ! ! where all the matrices are stored in CSR. On input and output the matrices -! are stored with column indices in local numbering, but inermediate quantities +! are stored with column indices in local numbering, but intermediate quantities ! are in global numbering because gathering the halo of B to multiply it ! by A implies a potential enlargement of the support. ! Also, B may have a column index space different from its row index space, @@ -61,98 +61,100 @@ ! info - integer, output. ! Error code. ! -!!$Subroutine psb_d_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) -!!$ use psb_base_mod, psb_protect_name => psb_d_par_csr_spspmm -!!$ Implicit None -!!$ -!!$ type(psb_d_csr_sparse_mat),intent(in) :: acsr -!!$ type(psb_d_csr_sparse_mat),intent(inout) :: bcsr -!!$ type(psb_d_csr_sparse_mat),intent(out) :: ccsr -!!$ type(psb_desc_type),intent(in) :: desc_a -!!$ type(psb_desc_type),intent(inout) :: desc_c -!!$ integer(psb_ipk_), intent(out) :: info -!!$ integer(psb_ipk_), intent(in), optional :: data -!!$ ! ...local scalars.... -!!$ integer(psb_ipk_) :: ictxt, np,me -!!$ integer(psb_ipk_) :: ncol, nnz -!!$ type(psb_d_csr_sparse_mat) :: tcsr1 -!!$ logical :: update_desc_c -!!$ integer(psb_ipk_) :: debug_level, debug_unit, err_act -!!$ character(len=20) :: name, ch_err -!!$ -!!$ if(psb_get_errstatus() /= 0) return -!!$ info=psb_success_ -!!$ name='psb_d_p_csr_spspmm' -!!$ call psb_erractionsave(err_act) -!!$ if (psb_errstatus_fatal()) then -!!$ info = psb_err_internal_error_ ; goto 9999 -!!$ end if -!!$ debug_unit = psb_get_debug_unit() -!!$ debug_level = psb_get_debug_level() -!!$ -!!$ ictxt = desc_a%get_context() -!!$ -!!$ call psb_info(ictxt, me, np) -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),': Start' -!!$ -!!$ update_desc_c = desc_c%is_bld() -!!$ -!!$ ! -!!$ ! This is a bit tricky. -!!$ ! DESC_A is the descriptor of (the columns of) A, and therefore -!!$ ! of the rows of B; the columns of B, in the intended usage, span -!!$ ! a different space for which we have DESC_C. -!!$ ! We are gathering the halo rows of B to multiply by A; -!!$ ! now, the columns of B would ideally be kept in -!!$ ! global numbering, so that we can call this repeatedly to accumulate -!!$ ! the product of multiple operators, and convert to local numbering -!!$ ! at the last possible moment. However, this would imply calling -!!$ ! the serial SPSPMM with a matrix B with the GLOBAL number of columns -!!$ ! and this could be very expensive in memory. The solution is to keep B -!!$ ! in local numbering, so that only columns really appearing count, but to -!!$ ! expand the descriptor when gathering the halo, because by performing -!!$ ! the products we are extending the support of the operator; hence -!!$ ! this routine is intended to be called with a temporary descriptor -!!$ ! DESC_C which is in the BUILD state, to allow for such expansion -!!$ ! across multiple products. -!!$ ! The caller will at some later point finalize the descriptor DESC_C. -!!$ ! -!!$ -!!$ ncol = desc_a%get_local_cols() -!!$ call psb_sphalo(bcsr,desc_a,tcsr1,info,& -!!$ & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) -!!$ nnz = tcsr1%get_nzeros() -!!$ if (update_desc_c) then -!!$ call desc_c%indxmap%g2lip_ins(tcsr1%ja(1:nnz),info) -!!$ else -!!$ call desc_c%indxmap%g2lip(tcsr1%ja(1:nnz),info) -!!$ end if -!!$ if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr1) -!!$ if (info == psb_success_) call tcsr1%free() -!!$ if(info /= psb_success_) then -!!$ call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') -!!$ goto 9999 -!!$ end if -!!$ call bcsr%set_ncols(desc_c%get_local_cols()) -!!$ -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm 3' -!!$ if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() -!!$ call psb_spspmm(acsr,bcsr,ccsr,info) -!!$ -!!$ call psb_erractionrestore(err_act) -!!$ return -!!$ -!!$9999 call psb_error_handler(ictxt,err_act) -!!$ -!!$ return -!!$ -!!$End Subroutine psb_d_par_csr_spspmm +Subroutine psb_d_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + use psb_base_mod, psb_protect_name => psb_d_par_csr_spspmm + Implicit None + + type(psb_d_csr_sparse_mat),intent(in) :: acsr + type(psb_d_csr_sparse_mat),intent(inout) :: bcsr + type(psb_d_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: ncol, nnz + type(psb_ld_csr_sparse_mat) :: ltcsr + type(psb_d_csr_sparse_mat) :: tcsr + logical :: update_desc_c + integer(psb_ipk_) :: debug_level, debug_unit, err_act + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='psb_d_p_csr_spspmm' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_a%get_context() + + call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + update_desc_c = desc_c%is_bld() + + ! + ! This is a bit tricky. + ! DESC_A is the descriptor of (the columns of) A, and therefore + ! of the rows of B; the columns of B, in the intended usage, span + ! a different space for which we have DESC_C. + ! We are gathering the halo rows of B to multiply by A; + ! now, the columns of B would ideally be kept in + ! global numbering, so that we can call this repeatedly to accumulate + ! the product of multiple operators, and convert to local numbering + ! at the last possible moment. However, this would imply calling + ! the serial SPSPMM with a matrix B with the GLOBAL number of columns + ! and this could be very expensive in memory. The solution is to keep B + ! in local numbering, so that only columns really appearing count, but to + ! expand the descriptor when gathering the halo, because by performing + ! the products we are extending the support of the operator; hence + ! this routine is intended to be called with a temporary descriptor + ! DESC_C which is in the BUILD state, to allow for such expansion + ! across multiple products. + ! The caller will at some later point finalize the descriptor DESC_C. + ! + + ncol = desc_a%get_local_cols() + call psb_sphalo(bcsr,desc_a,ltcsr,info,& + & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) + nnz = ltcsr%get_nzeros() + if (update_desc_c) then + call desc_c%indxmap%g2lip_ins(ltcsr%ja(1:nnz),info) + else + call desc_c%indxmap%g2lip(ltcsr%ja(1:nnz),info) + end if + call ltcsr%mv_to_ifmt(tcsr,info) + if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr) + if (info == psb_success_) call tcsr%free() + if(info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') + goto 9999 + end if + call bcsr%set_ncols(desc_c%get_local_cols()) + + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm 3' + if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() + call psb_spspmm(acsr,bcsr,ccsr,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +End Subroutine psb_d_par_csr_spspmm Subroutine psb_ld_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) use psb_base_mod, psb_protect_name => psb_ld_par_csr_spspmm diff --git a/base/tools/psb_dspasb.f90 b/base/tools/psb_dspasb.f90 index c2434c09c..542e6901e 100644 --- a/base/tools/psb_dspasb.f90 +++ b/base/tools/psb_dspasb.f90 @@ -122,11 +122,11 @@ subroutine psb_dspasb(a,desc_a, info, afmt, upd, dupl, mold) end if - IF (debug_level >= psb_debug_ext_) then + if (debug_level >= psb_debug_ext_) then ch_err=a%get_fmt() write(debug_unit, *) me,' ',trim(name),': From SPCNV',& & info,' ',ch_err - end IF + end if if (psb_errstatus_fatal()) then info=psb_err_from_subroutine_ diff --git a/base/tools/psb_dsphalo.F90 b/base/tools/psb_dsphalo.F90 index 032a139cd..8d800f6db 100644 --- a/base/tools/psb_dsphalo.F90 +++ b/base/tools/psb_dsphalo.F90 @@ -31,11 +31,26 @@ ! ! File: psb_dsphalo.f90 ! -! Subroutine: psb_dsphalo +! Subroutine: psb_dsphalo psb_ldsphalo ! This routine does the retrieval of remote matrix rows. -! Note that retrieval is done through GTBLK, therefore it should work -! for any matrix format in A; as for the output, default is CSR. -! +! Retrieval is done through GETROW, therefore it should work +! for any matrix format in A; as for the output, default is CSR. +! +! There is also a specialized version ld_CSR whose interface +! is adapted for the needs of d_par_csr_spspmm. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. ! ! Arguments: ! a - type(psb_dspmat_type) The local part of input matrix A @@ -55,9 +70,6 @@ ! psb_comm_ext_ use ext_index ! psb_comm_ovrl_ DISABLED for this routine. ! -#undef SP_A2AV_MPI -#undef SP_A2AV_XI -#define SP_A2AV_MAT Subroutine psb_dsphalo(a,desc_a,blk,info,rowcnv,colcnv,& & rowscale,colscale,outfmt,data) use psb_base_mod, psb_protect_name => psb_dsphalo @@ -314,16 +326,36 @@ Subroutine psb_dsphalo(a,desc_a,blk,info,rowcnv,colcnv,& call psb_errpush(info,name,a_err=ch_err); goto 9999 end if - - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,iarcv,jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& & iarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -390,16 +422,36 @@ Subroutine psb_dsphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -506,8 +558,7 @@ Subroutine psb_ldsphalo(a,desc_a,blk,info,rowcnv,colcnv,& integer(psb_ipk_), intent(in), optional :: data ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter, proc, i, & - & n_el_send,n_el_recv,& + integer(psb_ipk_) :: counter, proc, i, n_el_send,n_el_recv, & & n_elem, j, ipx,mat_recv, idxs,idxr,nz,& & data_,totxch,nxs, nxr, ncg integer(psb_lpk_) :: r, k, irmin, irmax, icmin, icmax, iszs, iszr, & @@ -718,16 +769,37 @@ Subroutine psb_ldsphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -829,12 +901,11 @@ Subroutine psb_ld_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& type(psb_desc_type),Intent(in), optional, target :: col_desc ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter,proc,i, & - & n_el_send,k,n_el_recv,r,& - & n_elem, j, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& - & irmin,icmin,data_,totxch,nxs, nxr,& - & err_act, nsnds, nrcvs - integer(psb_lpk_) :: ngtz,irmax,icmax,l1, lnr, lnc, lnnz, ncg, jpx, idx, tot_elem + integer(psb_ipk_) :: counter,proc,i, n_el_send,n_el_recv,& + & n_elem, j,ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & data_,totxch,nxs, nxr, err_act, nsnds, nrcvs + integer(psb_lpk_) :: ngtz,irmax,icmax,irmin,icmin,l1, lnr, lnc, lnnz, & + & r, k, ncg, jpx, idx, tot_elem integer(psb_mpk_) :: icomm, minfo integer(psb_mpk_), allocatable :: brvindx(:), & & rvsz(:), bsdindx(:),sdsz(:) @@ -1054,32 +1125,36 @@ Subroutine psb_ld_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if -#if defined(SP_A2AV_MPI) - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo /= mpi_success) info = minfo -#elif defined(SP_A2AV_XI) - call ld_my_a2av(valsnd,sdsz,bsdindx,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& & acoo%val,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(iasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& & acoo%ia,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(jasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& & acoo%ja,rvsz,brvindx,ictxt,info) -#elif defined(SP_A2AV_MAT) - call ld_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ipdxv,ictxt,icomm,info) -#else - choke on me @! -#endif + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -1163,185 +1238,376 @@ Subroutine psb_ld_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& return -#if defined(SP_A2AV_XI) || defined(SP_A2AV_MAT) -contains +End Subroutine psb_ld_csr_halo -#if defined(SP_A2AV_MAT) - subroutine ld_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & valrcv,iarcv,jarcv,rvsz,brvindx,ipdxv,ictxt,icomm,info) +Subroutine psb_d_ld_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + use psb_base_mod, psb_protect_name => psb_d_ld_csr_halo #ifdef MPI_MOD - use mpi + use mpi #endif - Implicit None + Implicit None #ifdef MPI_H - include 'mpif.h' + include 'mpif.h' #endif - real(psb_dpk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(in) :: ipdxv(:) - integer(psb_lpk_), intent(in) :: iasnd(:), jasnd(:) - real(psb_dpk_), intent(out) :: valrcv(:) - integer(psb_lpk_), intent(out) :: iarcv(:), jarcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_mpk_), intent(in) :: icomm - integer(psb_ipk_), intent(out) :: info - !Local variables - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter - integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret - integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(rowcnv)) then + rowcnv_ = rowcnv + else + rowcnv_ = .true. + endif + if (present(colcnv)) then + colcnv_ = colcnv + else + colcnv_ = .true. + endif + if (present(rowscale)) then + rowscale_ = rowscale + else + rowscale_ = .false. + endif + if (present(colscale)) then + colscale_ = colscale + else + colscale_ = .false. + endif + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + if (present(outcol_glob)) then + outcol_glob_ = outcol_glob + else + outcol_glob_ = .false. + endif + if (present(col_desc)) then + col_desc_ => col_desc + else + col_desc_ => desc_a + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + If (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Data selector',data_ + select case(data_) + case(psb_comm_halo_,psb_comm_ext_ ) + ! Do not accept OVRLAP_INDEX any longer. + case default + call psb_errpush(psb_err_from_subroutine_,name,a_err='wrong Data selector') + goto 9999 + end select - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - p2ptag = psb_double_swap_tag - call mpi_irecv(valrcv(idx+1:idx+sz),sz,& - & psb_mpi_r_dpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,1),iret) - p2ptag = psb_int_swap_tag - call mpi_irecv(iarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,2),iret) - call mpi_irecv(jarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,3),iret) - end if - counter = counter+n_el_send+3 + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + call desc_a%get_list(data_,pdxv,totxch,nxr,nxs,info) + ipdxv = pdxv%get_vect() + ! For all rows in the halo descriptor, extract the row size + lnr = 0 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + tot_elem = 0 + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + tot_elem = tot_elem+n_elem Enddo + sdsz(proc+1) = tot_elem + lnr = lnr + n_el_recv + counter = counter+n_el_send+3 + Enddo + ! + ! Exchange row sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! size of the rows may vary, as opposed to fixed + ! (multi) vector row size. + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - p2ptag = psb_double_swap_tag - call mpi_send(valsnd(idx+1:idx+sz),sz,& - & psb_mpi_r_dpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - p2ptag = psb_int_swap_tag - call mpi_send(iasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - call mpi_send(jasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) + idxs = 0 + idxr = 0 + counter = 1 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + counter = counter+n_el_send+3 + Enddo + + iszr = sum(rvsz) + mat_recv = iszr + iszs = sum(sdsz) + + lnnz = max(iszr,iszs,ione) + lnc = a%get_ncols() + call acoo%allocate(lnr,lnc,lnnz) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',acoo%get_size(),& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),liasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),ljasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + l1 = 0 + ipx = 1 + counter=1 + idx = 0 + ! + ! Make sure to get all columns in csget. + ! This is necessary when sphalo is used to compute a transpose, + ! as opposed to just gathering halo for spspmm purposes. + ! + ncg = huge(ncg) + tot_elem = 0 + Do + proc = ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + call a%csget(idx,idx,ngtz,iasnd,jasnd,valsnd,info,& + & append=.true.,nzin=tot_elem,jmax=ncg) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_sp_getrow') + goto 9999 end if - counter = counter+n_el_send+3 + tot_elem = tot_elem+ngtz Enddo + counter = counter+n_el_send+3 + Enddo + nz = tot_elem - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - sz = rvsz(ip+1) - if (sz > 0) then - call mpi_wait(rvhd(ip+1,1),p2pstat,iret) - call mpi_wait(rvhd(ip+1,2),p2pstat,iret) - call mpi_wait(rvhd(ip+1,3),p2pstat,iret) - end if - counter = counter+n_el_send+3 - Enddo + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Going for alltoallv',iszs,iszr + if (rowcnv_) then + call psb_loc_to_glob(iasnd(1:nz),liasnd(1:nz),desc_a,info,iact='I') + else + liasnd(1:nz) = iasnd(1:nz) + end if + if (colcnv_) then + call psb_loc_to_glob(jasnd(1:nz),ljasnd(1:nz),col_desc_,info,iact='I') + else + ljasnd(1:nz) = jasnd(1:nz) + end if + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_loc_to_glob') + goto 9999 + end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,liasnd,ljasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(liasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(ljasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(liasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(ljasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - end subroutine ld_coo_my_a2av -#endif -#if defined(SP_A2AV_XI) - subroutine ld_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - real(psb_dpk_), intent(in) :: valsnd(:) - real(psb_dpk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + ! + ! Convert into local numbering + ! + if (rowcnv_) call psb_glob_to_loc(acoo%ia(1:iszr),desc_a,info,iact='I') + ! + ! This seems to be the correct output condition + ! + if (colcnv_.and.(.not.outcol_glob_)) & + & call psb_glob_to_loc(acoo%ja(1:iszr),col_desc_,info,iact='I') - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psbglob_to_loc') + goto 9999 + end if - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))0).and.(k>0)) Then + l1=l1+1 + acoo%val(l1) = acoo%val(i) + acoo%ia(l1) = r + acoo%ja(l1) = k + irmin = min(irmin,r) + irmax = max(irmax,r) + icmin = min(icmin,k) + icmax = max(icmax,k) + End If + Enddo + if (rowscale_) then + call acoo%set_nrows(max(irmax-irmin+1,0)) + acoo%ia(1:l1) = acoo%ia(1:l1) - irmin + 1 + else + call acoo%set_nrows(irmax) + end if + if (colscale_) then + call acoo%set_ncols(max(icmax-icmin+1,0)) + acoo%ja(1:l1) = acoo%ja(1:l1) - icmin + 1 + else + call acoo%set_ncols(icmax) + end if - do ip = 0, np-1 - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do + call acoo%set_nzeros(l1) + call acoo%set_sorted(.false.) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine ld_my_a2av + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),& + & ': End data exchange',counter,l1 - subroutine i_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - integer(psb_ipk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info - + call acoo%fix(info) + if (info == psb_success_) call acoo%mv_to_fmt(blk,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_spcnv') + goto 9999 + end if - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do +9999 call psb_error_handler(ictxt,err_act) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine i_my_a2av -#endif -#endif -End Subroutine psb_ld_csr_halo + return + +End Subroutine psb_d_ld_csr_halo diff --git a/base/tools/psb_dspins.f90 b/base/tools/psb_dspins.F90 similarity index 99% rename from base/tools/psb_dspins.f90 rename to base/tools/psb_dspins.F90 index b774358b0..4018a36a8 100644 --- a/base/tools/psb_dspins.f90 +++ b/base/tools/psb_dspins.F90 @@ -288,6 +288,7 @@ subroutine psb_dspins_csr_lirp(nr,irp,ja,val,irw,a,desc_a,info,rebuild,local) end subroutine psb_dspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_dspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) use psb_base_mod, psb_protect_name => psb_dspins_csr_iirp use psi_mod @@ -384,6 +385,7 @@ subroutine psb_dspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) return end subroutine psb_dspins_csr_iirp +#endif subroutine psb_dspins_2desc(nz,ia,ja,val,a,desc_ar,desc_ac,info) use psb_base_mod, psb_protect_name => psb_dspins_2desc diff --git a/base/tools/psb_glob_to_loc.f90 b/base/tools/psb_glob_to_loc.f90 index 51b3f70d8..79799d195 100644 --- a/base/tools/psb_glob_to_loc.f90 +++ b/base/tools/psb_glob_to_loc.f90 @@ -60,10 +60,9 @@ subroutine psb_glob_to_loc2v(x,y,desc_a,info,iact,owned) !....locals.... integer(psb_ipk_) :: n, ictxt, iam, np - character :: act - integer(psb_ipk_) :: int_err(5), err_act - integer(psb_ipk_), parameter :: zero=0 - character(len=20) :: name + character :: act + integer(psb_ipk_) :: err_act + character(len=20) :: name if(psb_get_errstatus() /= 0) return info=psb_success_ @@ -181,10 +180,9 @@ subroutine psb_glob_to_loc1v(x,desc_a,info,iact,owned) !....locals.... integer(psb_ipk_) :: n - character :: act + character :: act integer(psb_ipk_) :: err_act - integer(psb_ipk_), parameter :: zero=0 - character(len=20) :: name + character(len=20) :: name integer(psb_ipk_) :: ictxt, iam, np if(psb_get_errstatus() /= 0) return diff --git a/base/tools/psb_i2allc_a.f90 b/base/tools/psb_i2allc_a.f90 new file mode 100644 index 000000000..3d453ea84 --- /dev/null +++ b/base/tools/psb_i2allc_a.f90 @@ -0,0 +1,246 @@ +! +! 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. +! +! +! +! File: psb_i2allc.f90 +! +! Function: psb_i2alloc +! Allocates dense matrix for PSBLAS routines. +! The descriptor may be in either the build or assembled state. +! +! Arguments: +! x - the matrix to be allocated. +! desc_a - the communication descriptor. +! info - Return code +! n - optional number of columns. +! lb - optional lower bound on column indices +subroutine psb_i2alloc(x, desc_a, info, n, lb) + use psb_base_mod, psb_protect_name => psb_i2alloc + use psi_mod + implicit none + + !....parameters... + integer(psb_i2pk_), allocatable, intent(out) :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: n, lb + + !locals + integer(psb_ipk_) :: err,nr,i,j,n_,err_act + integer(psb_ipk_) :: ictxt,np,me + integer(psb_ipk_) :: exch(3) + character(len=20) :: name + + name='psb_geall' + info = psb_success_ + err = 0 + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + !... check m and n parameters.... + if (.not.psb_is_ok_desc(desc_a)) then + info = psb_err_input_matrix_unassembled_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(n)) then + n_ = n + else + n_ = 1 + endif + !global check on n parameters + if (me == psb_root_) then + exch(1)=n_ + call psb_bcast(ictxt,exch(1),root=psb_root_) + else + call psb_bcast(ictxt,exch(1),root=psb_root_) + if (exch(1) /= n_) then + info=psb_err_parm_differs_among_procs_ + call psb_errpush(info,name,i_err=(/ione/)) + goto 9999 + endif + endif + + !....allocate x ..... + if (psb_is_asb_desc(desc_a).or.psb_is_upd_desc(desc_a)) then + nr = max(1,desc_a%get_local_cols()) + else if (psb_is_bld_desc(desc_a)) then + nr = max(1,desc_a%get_local_rows()) + else + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='Invalid desc_a') + goto 9999 + endif + + call psb_realloc(nr,n_,x,info,lb2=lb) + if (info /= psb_success_) then + info=psb_err_alloc_request_ + call psb_errpush(info,name,i_err=(/nr*n_/),a_err='integer(psb_i2pk_)') + goto 9999 + endif + + x(:,:) = i2zero + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2alloc + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! +! Function: psb_i2allocv +! Allocates dense matrix for PSBLAS routines +! The descriptor may be in either the build or assembled state. +! +! Arguments: +! x(:) - the matrix to be allocated. +! desc_a - the communication descriptor. +! info - return code +subroutine psb_i2allocv(x, desc_a,info,n) + use psb_base_mod, psb_protect_name => psb_i2allocv + use psi_mod + implicit none + + !....parameters... + integer(psb_i2pk_), allocatable, intent(out) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_),intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: n + + !locals + integer(psb_ipk_) :: nr,i,err_act + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name + + info=psb_success_ + name='psb_geall' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + ! ....verify blacs grid correctness.. + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + !... check m and n parameters.... + if (.not.psb_is_ok_desc(desc_a)) then + info = psb_err_input_matrix_unassembled_ + call psb_errpush(info,name) + goto 9999 + endif + + ! As this is a rank-1 array, optional parameter N is actually ignored. + + !....allocate x ..... + if (psb_is_asb_desc(desc_a).or.psb_is_upd_desc(desc_a)) then + nr = max(1,desc_a%get_local_cols()) + else if (psb_is_bld_desc(desc_a)) then + nr = max(1,desc_a%get_local_rows()) + else + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='Invalid desc_a') + goto 9999 + endif + + call psb_realloc(nr,x,info) + if (info /= psb_success_) then + info=psb_err_alloc_request_ + call psb_errpush(info,name,i_err=(/nr/),a_err='integer(psb_i2pk_)') + goto 9999 + endif + + x(:) = i2zero + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2allocv + diff --git a/base/tools/psb_i2asb_a.f90 b/base/tools/psb_i2asb_a.f90 new file mode 100644 index 000000000..4e7cc9b04 --- /dev/null +++ b/base/tools/psb_i2asb_a.f90 @@ -0,0 +1,259 @@ +! +! 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. +! +! +! File: psb_i2asb.f90 +! +! Subroutine: psb_i2asb +! Assembles a dense matrix for PSBLAS routines +! Since the allocation may have been called with the desciptor +! in the build state we make sure that X has a number of rows +! allowing for the halo indices, reallocating if necessary. +! We also call the halo routine for good measure. +! +! Arguments: +! x(:,:) - integer, allocatable The matrix to be assembled. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. return code +subroutine psb_i2asb(x, desc_a, info, scratch) + use psb_base_mod, psb_protect_name => psb_i2asb + implicit none + + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_), allocatable, intent(inout) :: x(:,:) + integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: scratch + + ! local variables + integer(psb_ipk_) :: ictxt,np,me,nrow,ncol, err_act + integer(psb_ipk_) :: i1sz, i2sz + integer(psb_ipk_) :: debug_level, debug_unit + logical :: scratch_ + character(len=20) :: name, ch_err + + info=psb_success_ + name='psb_i2geasb_m' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + scratch_ = .false. + if (present(scratch)) scratch_ = scratch + + if (.not.psb_is_ok_desc(desc_a)) then + info=psb_err_input_matrix_unassembled_ + call psb_errpush(info,name) + goto 9999 + endif + ictxt = desc_a%get_context() + + call psb_info(ictxt, me, np) + + + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': start: ',np,& + & desc_a%get_dectype() + ! ....verify blacs grid correctness.. + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + else if (.not.psb_is_asb_desc(desc_a)) then + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),' error ' + info = psb_err_input_matrix_unassembled_ + call psb_errpush(info,name) + goto 9999 + endif + + ! check size + ictxt = desc_a%get_context() + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + i1sz = size(x,dim=1) + i2sz = size(x,dim=2) + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': ',i1sz,i2sz,nrow,ncol + + if (i1sz < ncol) then + call psb_realloc(ncol,i2sz,x,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_realloc') + goto 9999 + endif + endif + + if (.not.scratch_) then + ! ..update halo elements.. + call psb_halo(x,desc_a,info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='psb_halo' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': end' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2asb + + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! Subroutine: psb_i2asb +! Assembles a dense matrix for PSBLAS routines +! Since the allocation may have been called with the desciptor +! in the build state we make sure that X has a number of rows +! allowing for the halo indices, reallocating if necessary. +! We also call the halo routine for good measure. +! +! Arguments: +! x(:) - integer, allocatable The matrix to be assembled. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +subroutine psb_i2asbv(x, desc_a, info, scratch) + use psb_base_mod, psb_protect_name => psb_i2asbv + implicit none + + type(psb_desc_type), intent(in) :: desc_a + integer(psb_i2pk_), allocatable, intent(inout) :: x(:) + integer(psb_ipk_), intent(out) :: info + logical, intent(in), optional :: scratch + + ! local variables + integer(psb_ipk_) :: ictxt,np,me + integer(psb_ipk_) :: i1sz,nrow,ncol, err_act + integer(psb_ipk_) :: debug_level, debug_unit + logical :: scratch_ + character(len=20) :: name,ch_err + + info = psb_success_ + name = 'psb_i2geasb_v' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + ictxt = desc_a%get_context() + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + scratch_ = .false. + if (present(scratch)) scratch_ = scratch + + call psb_info(ictxt, me, np) + + ! ....verify blacs grid correctness.. + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + else if (.not.psb_is_asb_desc(desc_a)) then + info = psb_err_input_matrix_unassembled_ + call psb_errpush(info,name) + goto 9999 + endif + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': sizes: ',nrow,ncol + i1sz = size(x) + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': sizes ',i1sz,ncol + if (i1sz < ncol) then + call psb_realloc(ncol,x,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_realloc') + goto 9999 + endif + endif + + if (.not.scratch_) then + ! ..update halo elements.. + call psb_halo(x,desc_a,info) + if(info /= psb_success_) then + info=psb_err_from_subroutine_ + ch_err='f90_pshalo' + call psb_errpush(info,name,a_err=ch_err) + goto 9999 + end if + end if + if (debug_level >= psb_debug_ext_) & + & write(debug_unit,*) me,' ',trim(name),': end' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2asbv diff --git a/base/tools/psb_i2free_a.f90 b/base/tools/psb_i2free_a.f90 new file mode 100644 index 000000000..5e6736261 --- /dev/null +++ b/base/tools/psb_i2free_a.f90 @@ -0,0 +1,164 @@ +! +! 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. +! +! +! File: psb_i2free.f90 +! +! Subroutine: psb_i2free +! frees a dense matrix structure +! +! Arguments: +! x(:,:) - integer, allocatable The dense matrix to be freed. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +subroutine psb_i2free(x, desc_a, info) + use psb_base_mod, psb_protect_name => psb_i2free + implicit none + + !....parameters... + integer(psb_i2pk_),allocatable, intent(inout) :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + !...locals.... + integer(psb_ipk_) :: ictxt,np,me, err_act + character(len=20) :: name + + name='psb_i2free' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (.not.psb_is_ok_desc(desc_a)) then + info=psb_err_forgot_spall_ + call psb_errpush(info,name) + return + end if + + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + ! ....verify blacs grid correctness.. + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + if (.not.allocated(x)) then + info=psb_err_forgot_spall_ + call psb_errpush(info,name) + goto 9999 + end if + + !deallocate x + deallocate(x,stat=info) + if (info /= psb_no_err_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + endif + + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2free + + + +! Subroutine: psb_i2freev +! frees a dense matrix structure +! +! Arguments: +! x(:) - integer, allocatable The dense matrix to be freed. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. Return code +subroutine psb_i2freev(x, desc_a, info) + use psb_base_mod, psb_protect_name => psb_i2freev + implicit none + !....parameters... + integer(psb_i2pk_),allocatable, intent(inout) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + + !...locals.... + integer(psb_ipk_) :: ictxt,np,me, err_act + character(len=20) :: name + + name='psb_i2freev' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (.not.psb_is_ok_desc(desc_a)) then + info=psb_err_forgot_spall_ + call psb_errpush(info,name) + goto 9999 + end if + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + + endif + + if (.not.allocated(x)) then + info=psb_err_forgot_spall_ + call psb_errpush(info,name) + goto 9999 + end if + + !deallocate x + deallocate(x,stat=info) + if (info /= psb_no_err_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + endif + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2freev diff --git a/base/tools/psb_i2ins_a.f90 b/base/tools/psb_i2ins_a.f90 new file mode 100644 index 000000000..76d7c260e --- /dev/null +++ b/base/tools/psb_i2ins_a.f90 @@ -0,0 +1,367 @@ +! +! 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. +! +! +! Subroutine: psb_i2insvi +! Insert dense submatrix to dense matrix. Note: the row indices in IRW +! are assumed to be in global numbering and are converted on the fly. +! Row indices not belonging to the current process are silently discarded. +! +! Arguments: +! m - integer. Number of rows of submatrix belonging to +! val to be inserted. +! irw(:) - integer Row indices of rows of val (global numbering) +! val(:) - integer The source dense submatrix. +! x(:) - integer The destination dense matrix. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. return code +! dupl - integer What to do with duplicates: +! psb_dupl_ovwrt_ overwrite +! psb_dupl_add_ add +subroutine psb_i2insvi(m, irw, val, x, desc_a, info, dupl,local) + use psb_base_mod, psb_protect_name => psb_i2insvi + use psi_mod + implicit none + + ! m rows number of submatrix belonging to val to be inserted + + ! ix x global-row corresponding to position at which val submatrix + ! must be inserted + + !....parameters... + integer(psb_ipk_), intent(in) :: m + integer(psb_lpk_), intent(in) :: irw(:) + integer(psb_i2pk_), intent(in) :: val(:) + integer(psb_i2pk_),intent(inout) :: x(:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: dupl + logical, intent(in), optional :: local + + !locals..... + integer(psb_ipk_) :: i, loc_rows,loc_cols,err_act + integer(psb_lpk_) :: mglob + integer(psb_ipk_) :: ictxt,np, me, dupl_ + integer(psb_ipk_), allocatable :: irl(:) + logical :: local_ + character(len=20) :: name + + name = 'psb_i2insvi' + info=psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (.not.desc_a%is_ok()) then + info = psb_err_invalid_cd_state_ + call psb_errpush(info,name) + return + end if + + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + !... check parameters.... + if (m < 0) then + info = psb_err_iarg_neg_ + call psb_errpush(info,name,i_err=(/ione,m/)) + goto 9999 + else if (size(x, dim=1) < desc_a%get_local_rows()) then + info = 310 + call psb_errpush(info,name,i_err=(/5_psb_ipk_,4_psb_ipk_/)) + goto 9999 + endif + + if (m == 0) return + loc_rows = desc_a%get_local_rows() + loc_cols = desc_a%get_local_cols() + mglob = desc_a%get_global_rows() + + allocate(irl(m),stat=info) + if (info /= psb_success_) then + info = psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + endif + + if (present(dupl)) then + dupl_ = dupl + else + dupl_ = psb_dupl_ovwrt_ + endif + if (present(local)) then + local_ = local + else + local_ = .false. + endif + + if (local_) then + irl(1:m) = irw(1:m) + else + call desc_a%indxmap%g2l(irw(1:m),irl(1:m),info,owned=.true.) + end if + select case(dupl_) + case(psb_dupl_ovwrt_) + do i = 1, m + !loop over all val's rows + + ! row actual block row + if (irl(i) > 0) then + ! this row belongs to me + ! copy i-th row of block val in x + x(irl(i)) = val(i) + end if + enddo + + case(psb_dupl_add_) + + do i = 1, m + !loop over all val's rows + + if (irl(i) > 0) then + ! this row belongs to me + ! copy i-th row of block val in x + x(irl(i)) = x(irl(i)) + val(i) + end if + enddo + + case default + info = 321 + call psb_errpush(info,name) + goto 9999 + end select + deallocate(irl) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2insvi + + + + +!!$ +!!$ Parallel Sparse BLAS version 3.5 +!!$ (C) Copyright 2006-2018 +!!$ Salvatore Filippone University of Rome Tor Vergata +!!$ 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. +!!$ +!!$ +! Subroutine: psb_i2insi +! Insert dense submatrix to dense matrix. Note: the row indices in IRW +! are assumed to be in global numbering and are converted on the fly. +! Row indices not belonging to the current process are silently discarded. +! +! Arguments: +! m - integer. Number of rows of submatrix belonging to +! val to be inserted. +! irw(:) - integer Row indices of rows of val (global numbering) +! val(:,:) - integer The source dense submatrix. +! x(:,:) - integer The destination dense matrix. +! desc_a - type(psb_desc_type). The communication descriptor. +! info - integer. return code +! dupl - integer What to do with duplicates: +! psb_dupl_ovwrt_ overwrite +! psb_dupl_add_ add +subroutine psb_i2insi(m, irw, val, x, desc_a, info, dupl,local) + use psb_base_mod, psb_protect_name => psb_i2insi + use psi_mod + implicit none + + ! m rows number of submatrix belonging to val to be inserted + + ! ix x global-row corresponding to position at which val submatrix + ! must be inserted + + !....parameters... + integer(psb_ipk_), intent(in) :: m + integer(psb_lpk_), intent(in) :: irw(:) + integer(psb_i2pk_), intent(in) :: val(:,:) + integer(psb_i2pk_),intent(inout) :: x(:,:) + type(psb_desc_type), intent(in) :: desc_a + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), optional, intent(in) :: dupl + logical, intent(in), optional :: local + + !locals..... + integer(psb_ipk_) :: i,loc_row,j,n, loc_rows,loc_cols,err_act + integer(psb_lpk_) :: mglob + integer(psb_ipk_) :: ictxt,np,me,dupl_ + integer(psb_ipk_), allocatable :: irl(:) + logical :: local_ + character(len=20) :: name + + name = 'psb_i2insi' + info = psb_success_ + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + + if (.not.desc_a%is_ok()) then + info = psb_err_invalid_cd_state_ + call psb_errpush(info,name) + return + end if + + ictxt=desc_a%get_context() + + call psb_info(ictxt, me, np) + if (np == -1) then + info = psb_err_context_error_ + call psb_errpush(info,name) + goto 9999 + endif + + !... check parameters.... + if (m < 0) then + info = psb_err_iarg_neg_ + call psb_errpush(info,name,i_err=(/ione,m/)) + goto 9999 + else if (size(x, dim=1) < desc_a%get_local_rows()) then + info = 310 + call psb_errpush(info,name,i_err=(/5_psb_ipk_,4_psb_ipk_/)) + goto 9999 + endif + if (m == 0) return + + loc_rows = desc_a%get_local_rows() + loc_cols = desc_a%get_local_cols() + mglob = desc_a%get_global_rows() + + n = min(size(val,2),size(x,2)) + + if (present(dupl)) then + dupl_ = dupl + else + dupl_ = psb_dupl_ovwrt_ + endif + + allocate(irl(m),stat=info) + if (info /= psb_success_) then + info = psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + endif + if (present(local)) then + local_ = local + else + local_ = .false. + endif + + if (local_) then + irl(1:m) = irw(1:m) + else + call desc_a%indxmap%g2l(irw(1:m),irl(1:m),info,owned=.true.) + end if + + select case(dupl_) + case(psb_dupl_ovwrt_) + do i = 1, m + !loop over all val's rows + + ! row actual block row + loc_row = irl(i) + if (loc_row > 0) then + ! this row belongs to me + ! copy i-th row of block val in x + do j=1,n + x(loc_row,j) = val(i,j) + end do + end if + enddo + + case(psb_dupl_add_) + + do i = 1, m + !loop over all val's rows + + ! row actual block row + loc_row = irl(i) + if (loc_row > 0) then + ! this row belongs to me + ! copy i-th row of block val in x + do j=1,n + x(loc_row,j) = x(loc_row,j) + val(i,j) + end do + end if + enddo + + case default + info = 321 + call psb_errpush(info,name) + goto 9999 + end select + deallocate(irl) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +end subroutine psb_i2insi + diff --git a/base/tools/psb_icdasb.F90 b/base/tools/psb_icdasb.F90 index 7176d1856..6b2ba1990 100644 --- a/base/tools/psb_icdasb.F90 +++ b/base/tools/psb_icdasb.F90 @@ -65,6 +65,10 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) integer(psb_ipk_) :: i, n_col, dectype, err_act, n_row integer(psb_mpk_) :: np,me, icomm, ictxt logical :: ext_hv_ + logical, parameter :: do_timings=.false. + integer(psb_ipk_), save :: idx_phase1=-1, idx_phase2=-1, idx_phase3=-1 + integer(psb_ipk_), save :: idx_phase11=-1, idx_phase12=-1, idx_phase13=-1 + integer(psb_ipk_), save :: idx_total=-1 integer(psb_ipk_) :: debug_level, debug_unit character(len=20) :: name @@ -81,7 +85,22 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) n_row = desc%get_local_rows() n_col = desc%get_local_cols() icomm = desc%get_mpic() + if ((do_timings).and.(idx_total==-1)) & + & idx_total = psb_get_timer_idx("ICDASB: total ") + if ((do_timings).and.(idx_phase1==-1)) & + & idx_phase1 = psb_get_timer_idx("ICDASB: phase1 ") + if ((do_timings).and.(idx_phase2==-1)) & + & idx_phase2 = psb_get_timer_idx("ICDASB: phase2") + if ((do_timings).and.(idx_phase3==-1)) & + & idx_phase3 = psb_get_timer_idx("ICDASB: phase3") +!!$ if ((do_timings).and.(idx_phase11==-1)) & +!!$ & idx_phase11 = psb_get_timer_idx("ICDASB: phase11 ") +!!$ if ((do_timings).and.(idx_phase12==-1)) & +!!$ & idx_phase12 = psb_get_timer_idx("ICDASB: phase12") +!!$ if ((do_timings).and.(idx_phase13==-1)) & +!!$ & idx_phase13 = psb_get_timer_idx("ICDASB: phase13") + call psb_tic(idx_total) ! check on blacs grid call psb_info(ictxt, me, np) if (np == -1) then @@ -115,6 +134,7 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) & write(debug_unit, *) me,' ',trim(name),': start' if (allocated(desc%indxmap)) then + if (do_timings) call psb_tic(idx_phase1) if (.not.ext_hv_) then call psi_bld_tmphalo(desc,info) if (info /= psb_success_) then @@ -122,7 +142,8 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) goto 9999 end if end if - + if (do_timings) call psb_toc(idx_phase1) + if (do_timings) call psb_tic(idx_phase2) ! Take out the lists for ovrlap, halo and ext... call psb_move_alloc(desc%ovrlap_index,ovrlap_index,info) call psb_move_alloc(desc%halo_index,halo_index,info) @@ -144,6 +165,8 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) call psb_errpush(info,name) goto 9999 end if + if (do_timings) call psb_toc(idx_phase2) + if (do_timings) call psb_tic(idx_phase3) call desc%indxmap%asb(info) if (info == psb_success_) then @@ -154,14 +177,14 @@ subroutine psb_icdasb(desc,info,ext_hv,mold) write(0,*) 'Error from internal indxmap asb ',info info = psb_success_ end if - + if (do_timings) call psb_toc(idx_phase3) else info = psb_err_invalid_cd_state_ call psb_errpush(info,name) goto 9999 endif - + call psb_toc(idx_total) if (debug_level >= psb_debug_ext_) & & write(debug_unit,*) me,' ',trim(name),': Done' diff --git a/base/tools/psb_s_glob_transpose.F90 b/base/tools/psb_s_glob_transpose.F90 new file mode 100644 index 000000000..afc4d3745 --- /dev/null +++ b/base/tools/psb_s_glob_transpose.F90 @@ -0,0 +1,902 @@ +! +! 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. +! +! +! File: psb_s_glob_transpose.f90 +! +! Subroutine: psb_s_glob_transpose +! Version: real +! +! This file provides multiple related versions of a parallel +! global transpose +! +! B = A^T +! +! There are some variations of this routine, that are accounted for +! in the workhorse psb_ls_coo_glob_transpose +! 1. The row and column spaces can share the same descriptor +! This essentially means that the descriptor relates to a +! matrix with a symmetric pattern. Examples are: symmetric +! matrices, matrices with symmetric pattern, lower or +! upper halves of such matrices +! 2. The row and column index spaces are different +! In this case you need to have two descriptor on input, +! plus if you want the output to be distributed according +! to the row descriptor, you will still need a new descriptor +! because even if the row distribution is the same, the pattern +! will be different. +! +! This is handled in the workhorse by having one mandatory and +! two optional descriptors: +! 1. If only the mandatory descriptor is present, then it is assumed that it +! is both row and column descriptor, and that it is sufficient. +! 2. If two descriptors are available, then use the second +! 3. If the third output descriptor is available, then rebuild it +! after the data exchange. +! +! The main transpose algorithm works like this: +! 1. Compute sizes: any entry A(I,J) with J in the halo will have +! to be sent to the process owning J, so walk through the +! matrix and compute all the send sizes, then do an alltoall to figure +! the receive sizes; +! 2. Adjust send bufffers; +! 3. Perform a local transpose; +! 4. Split the matrix: all local entries stay, all halo entries go into +! the send buffers, and are converted to global numbering; +! 5. Do the all-to-all (see below for a discussion of the alternative +! communication strategies) +! 6. The receive is in the extra section of the ACOO buffer; convert +! the row indices to local numbering, and discard extra ones (there will +! be some) +! 7. If desc_rx was requested, make sure to insert the (new) column indices +! 8. Cleanup and sort the output matrix +! 9. Copy back into AIN or ATRANS if requested. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. +! +! +subroutine psb_ls_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_ls_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_ls_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_ls_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_lpk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzt, nzd + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:) + real(psb_spk_), allocatable :: valsnd(:) + type(psb_ls_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),acoo%ia(nzl+1:nzl+iszr),& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(acoo%ja(nzl+1:nzl+nzt),info) + call psb_cdasb(desc_rx,info) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(acoo%ja(nzl+1:nzl+iszr),desc_r,info,iact='I') + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_ls_coo_glob_transpose + +subroutine psb_s_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_s_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_s_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_s_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_ipk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzd + integer(psb_lpk_) :: nzt, lszr + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:),iarcv(:),jarcv(:) + real(psb_spk_), allocatable :: valsnd(:) + type(psb_s_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),iarcv,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),jarcv,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),iarcv(1:iszr),& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv(1:iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & iarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(jarcv(1:nzt),info) + call psb_cdasb(desc_rx,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(jarcv(1:iszr),desc_r,info,iact='I') + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,& + & iarcv,jarcv,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_s_coo_glob_transpose + +subroutine psb_s_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_s_simple_glob_transpose_ip + implicit none + type(psb_sspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_s_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lsspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ') + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_s_simple_glob_transpose_ip + +subroutine psb_s_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_s_simple_glob_transpose + implicit none + type(psb_sspmat_type), intent(in) :: ain + type(psb_sspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_s_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lsspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ') + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_s_simple_glob_transpose + +subroutine psb_ls_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_ls_simple_glob_transpose_ip + implicit none + type(psb_lsspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_ls_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lsspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_ls_simple_glob_transpose_ip + +subroutine psb_ls_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_ls_simple_glob_transpose + implicit none + type(psb_lsspmat_type), intent(in) :: ain + type(psb_lsspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_ls_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lsspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_ls_simple_glob_transpose + + diff --git a/base/tools/psb_s_par_csr_spspmm.f90 b/base/tools/psb_s_par_csr_spspmm.f90 index b998ffc65..fba99f275 100644 --- a/base/tools/psb_s_par_csr_spspmm.f90 +++ b/base/tools/psb_s_par_csr_spspmm.f90 @@ -39,7 +39,7 @@ ! C = A * B ! ! where all the matrices are stored in CSR. On input and output the matrices -! are stored with column indices in local numbering, but inermediate quantities +! are stored with column indices in local numbering, but intermediate quantities ! are in global numbering because gathering the halo of B to multiply it ! by A implies a potential enlargement of the support. ! Also, B may have a column index space different from its row index space, @@ -61,98 +61,100 @@ ! info - integer, output. ! Error code. ! -!!$Subroutine psb_s_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) -!!$ use psb_base_mod, psb_protect_name => psb_s_par_csr_spspmm -!!$ Implicit None -!!$ -!!$ type(psb_s_csr_sparse_mat),intent(in) :: acsr -!!$ type(psb_s_csr_sparse_mat),intent(inout) :: bcsr -!!$ type(psb_s_csr_sparse_mat),intent(out) :: ccsr -!!$ type(psb_desc_type),intent(in) :: desc_a -!!$ type(psb_desc_type),intent(inout) :: desc_c -!!$ integer(psb_ipk_), intent(out) :: info -!!$ integer(psb_ipk_), intent(in), optional :: data -!!$ ! ...local scalars.... -!!$ integer(psb_ipk_) :: ictxt, np,me -!!$ integer(psb_ipk_) :: ncol, nnz -!!$ type(psb_s_csr_sparse_mat) :: tcsr1 -!!$ logical :: update_desc_c -!!$ integer(psb_ipk_) :: debug_level, debug_unit, err_act -!!$ character(len=20) :: name, ch_err -!!$ -!!$ if(psb_get_errstatus() /= 0) return -!!$ info=psb_success_ -!!$ name='psb_s_p_csr_spspmm' -!!$ call psb_erractionsave(err_act) -!!$ if (psb_errstatus_fatal()) then -!!$ info = psb_err_internal_error_ ; goto 9999 -!!$ end if -!!$ debug_unit = psb_get_debug_unit() -!!$ debug_level = psb_get_debug_level() -!!$ -!!$ ictxt = desc_a%get_context() -!!$ -!!$ call psb_info(ictxt, me, np) -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),': Start' -!!$ -!!$ update_desc_c = desc_c%is_bld() -!!$ -!!$ ! -!!$ ! This is a bit tricky. -!!$ ! DESC_A is the descriptor of (the columns of) A, and therefore -!!$ ! of the rows of B; the columns of B, in the intended usage, span -!!$ ! a different space for which we have DESC_C. -!!$ ! We are gathering the halo rows of B to multiply by A; -!!$ ! now, the columns of B would ideally be kept in -!!$ ! global numbering, so that we can call this repeatedly to accumulate -!!$ ! the product of multiple operators, and convert to local numbering -!!$ ! at the last possible moment. However, this would imply calling -!!$ ! the serial SPSPMM with a matrix B with the GLOBAL number of columns -!!$ ! and this could be very expensive in memory. The solution is to keep B -!!$ ! in local numbering, so that only columns really appearing count, but to -!!$ ! expand the descriptor when gathering the halo, because by performing -!!$ ! the products we are extending the support of the operator; hence -!!$ ! this routine is intended to be called with a temporary descriptor -!!$ ! DESC_C which is in the BUILD state, to allow for such expansion -!!$ ! across multiple products. -!!$ ! The caller will at some later point finalize the descriptor DESC_C. -!!$ ! -!!$ -!!$ ncol = desc_a%get_local_cols() -!!$ call psb_sphalo(bcsr,desc_a,tcsr1,info,& -!!$ & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) -!!$ nnz = tcsr1%get_nzeros() -!!$ if (update_desc_c) then -!!$ call desc_c%indxmap%g2lip_ins(tcsr1%ja(1:nnz),info) -!!$ else -!!$ call desc_c%indxmap%g2lip(tcsr1%ja(1:nnz),info) -!!$ end if -!!$ if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr1) -!!$ if (info == psb_success_) call tcsr1%free() -!!$ if(info /= psb_success_) then -!!$ call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') -!!$ goto 9999 -!!$ end if -!!$ call bcsr%set_ncols(desc_c%get_local_cols()) -!!$ -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm 3' -!!$ if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() -!!$ call psb_spspmm(acsr,bcsr,ccsr,info) -!!$ -!!$ call psb_erractionrestore(err_act) -!!$ return -!!$ -!!$9999 call psb_error_handler(ictxt,err_act) -!!$ -!!$ return -!!$ -!!$End Subroutine psb_s_par_csr_spspmm +Subroutine psb_s_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + use psb_base_mod, psb_protect_name => psb_s_par_csr_spspmm + Implicit None + + type(psb_s_csr_sparse_mat),intent(in) :: acsr + type(psb_s_csr_sparse_mat),intent(inout) :: bcsr + type(psb_s_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: ncol, nnz + type(psb_ls_csr_sparse_mat) :: ltcsr + type(psb_s_csr_sparse_mat) :: tcsr + logical :: update_desc_c + integer(psb_ipk_) :: debug_level, debug_unit, err_act + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='psb_s_p_csr_spspmm' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_a%get_context() + + call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + update_desc_c = desc_c%is_bld() + + ! + ! This is a bit tricky. + ! DESC_A is the descriptor of (the columns of) A, and therefore + ! of the rows of B; the columns of B, in the intended usage, span + ! a different space for which we have DESC_C. + ! We are gathering the halo rows of B to multiply by A; + ! now, the columns of B would ideally be kept in + ! global numbering, so that we can call this repeatedly to accumulate + ! the product of multiple operators, and convert to local numbering + ! at the last possible moment. However, this would imply calling + ! the serial SPSPMM with a matrix B with the GLOBAL number of columns + ! and this could be very expensive in memory. The solution is to keep B + ! in local numbering, so that only columns really appearing count, but to + ! expand the descriptor when gathering the halo, because by performing + ! the products we are extending the support of the operator; hence + ! this routine is intended to be called with a temporary descriptor + ! DESC_C which is in the BUILD state, to allow for such expansion + ! across multiple products. + ! The caller will at some later point finalize the descriptor DESC_C. + ! + + ncol = desc_a%get_local_cols() + call psb_sphalo(bcsr,desc_a,ltcsr,info,& + & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) + nnz = ltcsr%get_nzeros() + if (update_desc_c) then + call desc_c%indxmap%g2lip_ins(ltcsr%ja(1:nnz),info) + else + call desc_c%indxmap%g2lip(ltcsr%ja(1:nnz),info) + end if + call ltcsr%mv_to_ifmt(tcsr,info) + if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr) + if (info == psb_success_) call tcsr%free() + if(info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') + goto 9999 + end if + call bcsr%set_ncols(desc_c%get_local_cols()) + + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm 3' + if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() + call psb_spspmm(acsr,bcsr,ccsr,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +End Subroutine psb_s_par_csr_spspmm Subroutine psb_ls_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) use psb_base_mod, psb_protect_name => psb_ls_par_csr_spspmm diff --git a/base/tools/psb_sspasb.f90 b/base/tools/psb_sspasb.f90 index 58241a922..01187497a 100644 --- a/base/tools/psb_sspasb.f90 +++ b/base/tools/psb_sspasb.f90 @@ -122,11 +122,11 @@ subroutine psb_sspasb(a,desc_a, info, afmt, upd, dupl, mold) end if - IF (debug_level >= psb_debug_ext_) then + if (debug_level >= psb_debug_ext_) then ch_err=a%get_fmt() write(debug_unit, *) me,' ',trim(name),': From SPCNV',& & info,' ',ch_err - end IF + end if if (psb_errstatus_fatal()) then info=psb_err_from_subroutine_ diff --git a/base/tools/psb_ssphalo.F90 b/base/tools/psb_ssphalo.F90 index 1cd942f12..038e72a51 100644 --- a/base/tools/psb_ssphalo.F90 +++ b/base/tools/psb_ssphalo.F90 @@ -31,11 +31,26 @@ ! ! File: psb_ssphalo.f90 ! -! Subroutine: psb_ssphalo +! Subroutine: psb_ssphalo psb_lssphalo ! This routine does the retrieval of remote matrix rows. -! Note that retrieval is done through GTBLK, therefore it should work -! for any matrix format in A; as for the output, default is CSR. -! +! Retrieval is done through GETROW, therefore it should work +! for any matrix format in A; as for the output, default is CSR. +! +! There is also a specialized version ls_CSR whose interface +! is adapted for the needs of s_par_csr_spspmm. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. ! ! Arguments: ! a - type(psb_sspmat_type) The local part of input matrix A @@ -55,9 +70,6 @@ ! psb_comm_ext_ use ext_index ! psb_comm_ovrl_ DISABLED for this routine. ! -#undef SP_A2AV_MPI -#undef SP_A2AV_XI -#define SP_A2AV_MAT Subroutine psb_ssphalo(a,desc_a,blk,info,rowcnv,colcnv,& & rowscale,colscale,outfmt,data) use psb_base_mod, psb_protect_name => psb_ssphalo @@ -314,16 +326,36 @@ Subroutine psb_ssphalo(a,desc_a,blk,info,rowcnv,colcnv,& call psb_errpush(info,name,a_err=ch_err); goto 9999 end if - - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,iarcv,jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& & iarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -390,16 +422,36 @@ Subroutine psb_ssphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -506,8 +558,7 @@ Subroutine psb_lssphalo(a,desc_a,blk,info,rowcnv,colcnv,& integer(psb_ipk_), intent(in), optional :: data ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter, proc, i, & - & n_el_send,n_el_recv,& + integer(psb_ipk_) :: counter, proc, i, n_el_send,n_el_recv, & & n_elem, j, ipx,mat_recv, idxs,idxr,nz,& & data_,totxch,nxs, nxr, ncg integer(psb_lpk_) :: r, k, irmin, irmax, icmin, icmax, iszs, iszr, & @@ -718,16 +769,37 @@ Subroutine psb_lssphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -829,12 +901,11 @@ Subroutine psb_ls_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& type(psb_desc_type),Intent(in), optional, target :: col_desc ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter,proc,i, & - & n_el_send,k,n_el_recv,r,& - & n_elem, j, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& - & irmin,icmin,data_,totxch,nxs, nxr,& - & err_act, nsnds, nrcvs - integer(psb_lpk_) :: ngtz,irmax,icmax,l1, lnr, lnc, lnnz, ncg, jpx, idx, tot_elem + integer(psb_ipk_) :: counter,proc,i, n_el_send,n_el_recv,& + & n_elem, j,ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & data_,totxch,nxs, nxr, err_act, nsnds, nrcvs + integer(psb_lpk_) :: ngtz,irmax,icmax,irmin,icmin,l1, lnr, lnc, lnnz, & + & r, k, ncg, jpx, idx, tot_elem integer(psb_mpk_) :: icomm, minfo integer(psb_mpk_), allocatable :: brvindx(:), & & rvsz(:), bsdindx(:),sdsz(:) @@ -1054,32 +1125,36 @@ Subroutine psb_ls_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if -#if defined(SP_A2AV_MPI) - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& - & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo /= mpi_success) info = minfo -#elif defined(SP_A2AV_XI) - call ls_my_a2av(valsnd,sdsz,bsdindx,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& & acoo%val,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(iasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& & acoo%ia,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(jasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& & acoo%ja,rvsz,brvindx,ictxt,info) -#elif defined(SP_A2AV_MAT) - call ls_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ipdxv,ictxt,icomm,info) -#else - choke on me @! -#endif + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -1163,185 +1238,376 @@ Subroutine psb_ls_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& return -#if defined(SP_A2AV_XI) || defined(SP_A2AV_MAT) -contains +End Subroutine psb_ls_csr_halo -#if defined(SP_A2AV_MAT) - subroutine ls_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & valrcv,iarcv,jarcv,rvsz,brvindx,ipdxv,ictxt,icomm,info) +Subroutine psb_s_ls_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + use psb_base_mod, psb_protect_name => psb_s_ls_csr_halo #ifdef MPI_MOD - use mpi + use mpi #endif - Implicit None + Implicit None #ifdef MPI_H - include 'mpif.h' + include 'mpif.h' #endif - real(psb_spk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(in) :: ipdxv(:) - integer(psb_lpk_), intent(in) :: iasnd(:), jasnd(:) - real(psb_spk_), intent(out) :: valrcv(:) - integer(psb_lpk_), intent(out) :: iarcv(:), jarcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_mpk_), intent(in) :: icomm - integer(psb_ipk_), intent(out) :: info - !Local variables - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter - integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret - integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(rowcnv)) then + rowcnv_ = rowcnv + else + rowcnv_ = .true. + endif + if (present(colcnv)) then + colcnv_ = colcnv + else + colcnv_ = .true. + endif + if (present(rowscale)) then + rowscale_ = rowscale + else + rowscale_ = .false. + endif + if (present(colscale)) then + colscale_ = colscale + else + colscale_ = .false. + endif + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + if (present(outcol_glob)) then + outcol_glob_ = outcol_glob + else + outcol_glob_ = .false. + endif + if (present(col_desc)) then + col_desc_ => col_desc + else + col_desc_ => desc_a + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + If (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Data selector',data_ + select case(data_) + case(psb_comm_halo_,psb_comm_ext_ ) + ! Do not accept OVRLAP_INDEX any longer. + case default + call psb_errpush(psb_err_from_subroutine_,name,a_err='wrong Data selector') + goto 9999 + end select - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - p2ptag = psb_real_swap_tag - call mpi_irecv(valrcv(idx+1:idx+sz),sz,& - & psb_mpi_r_spk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,1),iret) - p2ptag = psb_int_swap_tag - call mpi_irecv(iarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,2),iret) - call mpi_irecv(jarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,3),iret) - end if - counter = counter+n_el_send+3 + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + call desc_a%get_list(data_,pdxv,totxch,nxr,nxs,info) + ipdxv = pdxv%get_vect() + ! For all rows in the halo descriptor, extract the row size + lnr = 0 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + tot_elem = 0 + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + tot_elem = tot_elem+n_elem Enddo + sdsz(proc+1) = tot_elem + lnr = lnr + n_el_recv + counter = counter+n_el_send+3 + Enddo + ! + ! Exchange row sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! size of the rows may vary, as opposed to fixed + ! (multi) vector row size. + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - p2ptag = psb_real_swap_tag - call mpi_send(valsnd(idx+1:idx+sz),sz,& - & psb_mpi_r_spk_,prcid(ip+1),& - & p2ptag, icomm,iret) - p2ptag = psb_int_swap_tag - call mpi_send(iasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - call mpi_send(jasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) + idxs = 0 + idxr = 0 + counter = 1 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + counter = counter+n_el_send+3 + Enddo + + iszr = sum(rvsz) + mat_recv = iszr + iszs = sum(sdsz) + + lnnz = max(iszr,iszs,ione) + lnc = a%get_ncols() + call acoo%allocate(lnr,lnc,lnnz) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',acoo%get_size(),& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),liasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),ljasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + l1 = 0 + ipx = 1 + counter=1 + idx = 0 + ! + ! Make sure to get all columns in csget. + ! This is necessary when sphalo is used to compute a transpose, + ! as opposed to just gathering halo for spspmm purposes. + ! + ncg = huge(ncg) + tot_elem = 0 + Do + proc = ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + call a%csget(idx,idx,ngtz,iasnd,jasnd,valsnd,info,& + & append=.true.,nzin=tot_elem,jmax=ncg) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_sp_getrow') + goto 9999 end if - counter = counter+n_el_send+3 + tot_elem = tot_elem+ngtz Enddo + counter = counter+n_el_send+3 + Enddo + nz = tot_elem - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - sz = rvsz(ip+1) - if (sz > 0) then - call mpi_wait(rvhd(ip+1,1),p2pstat,iret) - call mpi_wait(rvhd(ip+1,2),p2pstat,iret) - call mpi_wait(rvhd(ip+1,3),p2pstat,iret) - end if - counter = counter+n_el_send+3 - Enddo + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Going for alltoallv',iszs,iszr + if (rowcnv_) then + call psb_loc_to_glob(iasnd(1:nz),liasnd(1:nz),desc_a,info,iact='I') + else + liasnd(1:nz) = iasnd(1:nz) + end if + if (colcnv_) then + call psb_loc_to_glob(jasnd(1:nz),ljasnd(1:nz),col_desc_,info,iact='I') + else + ljasnd(1:nz) = jasnd(1:nz) + end if + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_loc_to_glob') + goto 9999 + end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,liasnd,ljasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(liasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(ljasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_r_spk_,& + & acoo%val,rvsz,brvindx,psb_mpi_r_spk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(liasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(ljasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - end subroutine ls_coo_my_a2av -#endif -#if defined(SP_A2AV_XI) - subroutine ls_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - real(psb_spk_), intent(in) :: valsnd(:) - real(psb_spk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + ! + ! Convert into local numbering + ! + if (rowcnv_) call psb_glob_to_loc(acoo%ia(1:iszr),desc_a,info,iact='I') + ! + ! This seems to be the correct output condition + ! + if (colcnv_.and.(.not.outcol_glob_)) & + & call psb_glob_to_loc(acoo%ja(1:iszr),col_desc_,info,iact='I') - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psbglob_to_loc') + goto 9999 + end if - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))0).and.(k>0)) Then + l1=l1+1 + acoo%val(l1) = acoo%val(i) + acoo%ia(l1) = r + acoo%ja(l1) = k + irmin = min(irmin,r) + irmax = max(irmax,r) + icmin = min(icmin,k) + icmax = max(icmax,k) + End If + Enddo + if (rowscale_) then + call acoo%set_nrows(max(irmax-irmin+1,0)) + acoo%ia(1:l1) = acoo%ia(1:l1) - irmin + 1 + else + call acoo%set_nrows(irmax) + end if + if (colscale_) then + call acoo%set_ncols(max(icmax-icmin+1,0)) + acoo%ja(1:l1) = acoo%ja(1:l1) - icmin + 1 + else + call acoo%set_ncols(icmax) + end if - do ip = 0, np-1 - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do + call acoo%set_nzeros(l1) + call acoo%set_sorted(.false.) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine ls_my_a2av + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),& + & ': End data exchange',counter,l1 - subroutine i_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - integer(psb_ipk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info - + call acoo%fix(info) + if (info == psb_success_) call acoo%mv_to_fmt(blk,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_spcnv') + goto 9999 + end if - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do +9999 call psb_error_handler(ictxt,err_act) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine i_my_a2av -#endif -#endif -End Subroutine psb_ls_csr_halo + return + +End Subroutine psb_s_ls_csr_halo diff --git a/base/tools/psb_sspins.f90 b/base/tools/psb_sspins.F90 similarity index 99% rename from base/tools/psb_sspins.f90 rename to base/tools/psb_sspins.F90 index e1cea6198..7a86e5594 100644 --- a/base/tools/psb_sspins.f90 +++ b/base/tools/psb_sspins.F90 @@ -288,6 +288,7 @@ subroutine psb_sspins_csr_lirp(nr,irp,ja,val,irw,a,desc_a,info,rebuild,local) end subroutine psb_sspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_sspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) use psb_base_mod, psb_protect_name => psb_sspins_csr_iirp use psi_mod @@ -384,6 +385,7 @@ subroutine psb_sspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) return end subroutine psb_sspins_csr_iirp +#endif subroutine psb_sspins_2desc(nz,ia,ja,val,a,desc_ar,desc_ac,info) use psb_base_mod, psb_protect_name => psb_sspins_2desc diff --git a/base/tools/psb_z_glob_transpose.F90 b/base/tools/psb_z_glob_transpose.F90 new file mode 100644 index 000000000..64cf534b5 --- /dev/null +++ b/base/tools/psb_z_glob_transpose.F90 @@ -0,0 +1,902 @@ +! +! 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. +! +! +! File: psb_z_glob_transpose.f90 +! +! Subroutine: psb_z_glob_transpose +! Version: complex +! +! This file provides multiple related versions of a parallel +! global transpose +! +! B = A^T +! +! There are some variations of this routine, that are accounted for +! in the workhorse psb_lz_coo_glob_transpose +! 1. The row and column spaces can share the same descriptor +! This essentially means that the descriptor relates to a +! matrix with a symmetric pattern. Examples are: symmetric +! matrices, matrices with symmetric pattern, lower or +! upper halves of such matrices +! 2. The row and column index spaces are different +! In this case you need to have two descriptor on input, +! plus if you want the output to be distributed according +! to the row descriptor, you will still need a new descriptor +! because even if the row distribution is the same, the pattern +! will be different. +! +! This is handled in the workhorse by having one mandatory and +! two optional descriptors: +! 1. If only the mandatory descriptor is present, then it is assumed that it +! is both row and column descriptor, and that it is sufficient. +! 2. If two descriptors are available, then use the second +! 3. If the third output descriptor is available, then rebuild it +! after the data exchange. +! +! The main transpose algorithm works like this: +! 1. Compute sizes: any entry A(I,J) with J in the halo will have +! to be sent to the process owning J, so walk through the +! matrix and compute all the send sizes, then do an alltoall to figure +! the receive sizes; +! 2. Adjust send bufffers; +! 3. Perform a local transpose; +! 4. Split the matrix: all local entries stay, all halo entries go into +! the send buffers, and are converted to global numbering; +! 5. Do the all-to-all (see below for a discussion of the alternative +! communication strategies) +! 6. The receive is in the extra section of the ACOO buffer; convert +! the row indices to local numbering, and discard extra ones (there will +! be some) +! 7. If desc_rx was requested, make sure to insert the (new) column indices +! 8. Cleanup and sort the output matrix +! 9. Copy back into AIN or ATRANS if requested. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. +! +! +subroutine psb_lz_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_lz_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_lz_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_lz_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_lpk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzt, nzd + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:) + complex(psb_dpk_), allocatable :: valsnd(:) + type(psb_lz_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),acoo%ia(nzl+1:nzl+iszr),& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(acoo%ja(nzl+1:nzl+nzt),info) + call psb_cdasb(desc_rx,info) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(acoo%ia(nzl+1:nzl+iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(acoo%ja(nzl+1:nzl+iszr),desc_r,info,iact='I') + call psb_coo_clean_negidx_inner(iszr,acoo%ia(nzl+1:nzl+iszr),acoo%ja(nzl+1:nzl+iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_lz_coo_glob_transpose + +subroutine psb_z_coo_glob_transpose(ain,desc_r,info,atrans,desc_c,desc_rx) +#ifdef MPI_MOD + use mpi +#endif + use psb_base_mod, psb_protect_name => psb_z_coo_glob_transpose + Implicit None +#ifdef MPI_H + include 'mpif.h' +#endif + type(psb_z_coo_sparse_mat), intent(inout) :: ain + type(psb_desc_type), intent(inout), target :: desc_r + type(psb_z_coo_sparse_mat), intent(out), optional :: atrans + type(psb_desc_type), intent(inout), target, optional :: desc_c + type(psb_desc_type), intent(out), optional :: desc_rx + integer(psb_ipk_), intent(out) :: info + + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: counter,proc, err_act, j + integer(psb_ipk_) :: i, k, idx, r, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & l1, nsnds, nrcvs, nr,nc,nzl, hlstart, nzd + integer(psb_lpk_) :: nzt, lszr + integer(psb_mpk_) :: icomm, minfo + integer(psb_mpk_), allocatable :: brvindx(:), & + & rvsz(:), bsdindx(:), sdsz(:), tsdx(:), trvx(:) + integer(psb_ipk_), allocatable :: halo_owner(:) + integer(psb_lpk_), allocatable :: iasnd(:), jasnd(:),iarcv(:),jarcv(:) + complex(psb_dpk_), allocatable :: valsnd(:) + type(psb_z_coo_sparse_mat), allocatable :: acoo + logical :: rowcnv_,colcnv_,rowscale_,colscale_,outcol_glob_ + type(psb_desc_type), pointer :: p_desc_c + character(len=5) :: outfmt_ + integer(psb_ipk_) :: debug_level, debug_unit + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='mld_glob_transpose' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_r%get_context() + icomm = desc_r%get_mpic() + + Call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(desc_c)) then + p_desc_c => desc_c + else + p_desc_c => desc_r + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + if (present(atrans)) then + call ain%cp_to_coo(acoo,info) + else + call ain%mv_to_coo(acoo,info) + end if + + + ! + ! Compute number of entries in the + ! halo part, sorted by destination process + ! + nr = desc_r%get_local_rows() + nc = p_desc_c%get_local_cols() + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + do k=1, nzl + j = acoo%ja(k) + if (j > hlstart) then + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + sdsz(proc+1) = sdsz(proc+1) +1 + end if + end do + + ! + ! Exchange sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! number of entries was not precomputed in the descriptor, + ! which was vector-oriented and not matrix-entry-oriented + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs + + idxs = 0 + idxr = 0 + counter = 1 + Do proc = 0, np-1 + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + Enddo + + tsdx = bsdindx + trvx = brvindx + + iszr = sum(rvsz) + iszs = sum(sdsz) + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),iarcv,info) + if (info == psb_success_) call psb_ensure_size(max(iszr,1),jarcv,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + ! + ! Now, transpose the matrix, then split between itself + ! and the send buffers + ! + call acoo%transp() + if (acoo%get_nzeros()/= nzl) then + write(0,*) me,'Something strange upon transpose: ',nzl,acoo%get_nzeros() + end if + nzl = acoo%get_nzeros() + hlstart = p_desc_c%get_local_rows() + + + nzd = 0 + do k = 1, nzl + j = acoo%ia(k) + if (j<=hlstart) then + nzd = nzd + 1 + acoo%ia(nzd) = acoo%ia(k) + acoo%ja(nzd) = acoo%ja(k) + acoo%val(nzd) = acoo%val(k) + else + call p_desc_c%indxmap%fnd_halo_owner(j,proc,info) + tsdx(proc+1) = tsdx(proc+1) +1 + iasnd(tsdx(proc+1)) = acoo%ia(k) + jasnd(tsdx(proc+1)) = acoo%ja(k) + valsnd(tsdx(proc+1)) = acoo%val(k) + end if + end do + call acoo%set_nzeros(nzd) + ! + ! Put halo entries in global numbering + ! + call desc_r%indxmap%l2gip(jasnd(1:iszs),info) + call p_desc_c%indxmap%l2gip(iasnd(1:iszs),info) + ! And exchange data. + ! Normally we'll use our SIMPLE A2AV and not MPI, because + ! the communication pattern is sparse, so ours is more + ! efficient. Using ACOO for the receive buffers. + nzl = acoo%get_nzeros() + call acoo%ensure_size(nzl+iszr) + + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),iarcv(1:iszr),& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv(1:iszr),rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv(1:iszr),rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val(nzl+1:nzl+iszr),rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & iarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv(1:iszr),rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + + if (present(desc_rx)) then + ! + ! Extend the appropriate descriptor; started as R but on + ! transpose it now describes C + ! + call desc_r%clone(desc_rx,info) + call psb_cd_reinit(desc_rx,info) + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + call desc_rx%g2lip_ins(jarcv(1:nzt),info) + call psb_cdasb(desc_rx,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + ! + ! Insert to extend descriptor + ! + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_rx%get_local_cols()) + !write(0,*) me,' Trans RX ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + else + ! + ! + ! Take out non-local rows + ! + call psb_glob_to_loc(iarcv(1:iszr),p_desc_c,info,iact='I',owned=.true.) + call psb_glob_to_loc(jarcv(1:iszr),desc_r,info,iact='I') + lszr = iszr + call psb_coo_clean_negidx_inner(lszr,iarcv(1:iszr),jarcv(1:iszr),& + & acoo%val(nzl+1:nzl+iszr),nzt,info) + acoo%ia(nzl+1:nzl+nzt) = iarcv(1:nzt) + acoo%ja(nzl+1:nzl+nzt) = jarcv(1:nzt) + nzl = nzl + nzt + call acoo%set_nzeros(nzl) + nzl = acoo%get_nzeros() + call acoo%set_sorted(.false.) + + call acoo%set_nrows(p_desc_c%get_local_rows()) + call acoo%set_ncols(desc_r%get_local_cols()) + !write(0,*) me,' Trans R- ',acoo%get_nrows(),acoo%get_ncols(),acoo%get_nzeros() + end if + +!!$ write(0,*) me,' Sanity check after rx%g2l :',count(acoo%ja(1:nzl)<0) + + + call acoo%fix(info) + nzl = acoo%get_nzeros() + + if (present(atrans)) then + call atrans%mv_from_coo(acoo,info) + else + call ain%mv_from_coo(acoo,info) + end if + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,& + & iarcv,jarcv,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return +end subroutine psb_z_coo_glob_transpose + +subroutine psb_z_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_z_simple_glob_transpose_ip + implicit none + type(psb_zspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_z_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lzspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ') + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_z_simple_glob_transpose_ip + +subroutine psb_z_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_z_simple_glob_transpose + implicit none + type(psb_zspmat_type), intent(in) :: ain + type(psb_zspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_z_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lzspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ') + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_z_simple_glob_transpose + +subroutine psb_lz_simple_glob_transpose_ip(ain,desc_a,info) + use psb_base_mod, psb_protect_name => psb_lz_simple_glob_transpose_ip + implicit none + type(psb_lzspmat_type), intent(inout) :: ain + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_lz_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%mv_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call ain%mv_from(tmpc2) + + if (dump) then + block + type(psb_lzspmat_type) :: aglb + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call ain%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,ain,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_lz_simple_glob_transpose_ip + +subroutine psb_lz_simple_glob_transpose(ain,aout,desc_a,info) + use psb_base_mod, psb_protect_name => psb_lz_simple_glob_transpose + implicit none + type(psb_lzspmat_type), intent(in) :: ain + type(psb_lzspmat_type), intent(out) :: aout + type(psb_desc_type) :: desc_a + integer(psb_ipk_), intent(out) :: info + + ! + ! BEWARE: This routine works under the assumption + ! that the same DESC_A works for both A and A^T, which + ! essentially means that A has a symmetric pattern. + ! + type(psb_lz_coo_sparse_mat) :: tmpc1, tmpc2 + integer(psb_ipk_) :: nz1, nz2, nzh, nz + integer(psb_ipk_) :: ictxt, me, np + integer(psb_lpk_) :: i, j, k, nrow, ncol, nlz + integer(psb_lpk_), allocatable :: ilv(:) + character(len=80) :: aname + logical, parameter :: debug=.false., dump=.false., debug_sync=.false. + + ictxt = desc_a%get_context() + call psb_info(ictxt,me,np) + + nrow = desc_a%get_local_rows() + ncol = desc_a%get_local_cols() + if (debug_sync) then + call psb_barrier(ictxt) + if (me == 0) write(0,*) 'Start htranspose ' + end if + + + call ain%cp_to(tmpc1) + call psb_glob_transpose(tmpc1, desc_a,info,atrans=tmpc2) + call aout%mv_from(tmpc2) + + if (dump) then + block + type(psb_lzspmat_type) :: aglb + + write(aname,'(a,i3.3,a)') 'atran-',me,'.mtx' + call aout%print(fname=aname,head='atrans ',iv=ilv) + call psb_gather(aglb,aout,desc_a,info) + if (me==psb_root_) then + write(aname,'(a,i3.3,a)') 'atran.mtx' + call aglb%print(fname=aname,head='Test ') + end if + end block + end if + +end subroutine psb_lz_simple_glob_transpose + + diff --git a/base/tools/psb_z_par_csr_spspmm.f90 b/base/tools/psb_z_par_csr_spspmm.f90 index 71e1b7eeb..3be9d0e8c 100644 --- a/base/tools/psb_z_par_csr_spspmm.f90 +++ b/base/tools/psb_z_par_csr_spspmm.f90 @@ -39,7 +39,7 @@ ! C = A * B ! ! where all the matrices are stored in CSR. On input and output the matrices -! are stored with column indices in local numbering, but inermediate quantities +! are stored with column indices in local numbering, but intermediate quantities ! are in global numbering because gathering the halo of B to multiply it ! by A implies a potential enlargement of the support. ! Also, B may have a column index space different from its row index space, @@ -61,98 +61,100 @@ ! info - integer, output. ! Error code. ! -!!$Subroutine psb_z_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) -!!$ use psb_base_mod, psb_protect_name => psb_z_par_csr_spspmm -!!$ Implicit None -!!$ -!!$ type(psb_z_csr_sparse_mat),intent(in) :: acsr -!!$ type(psb_z_csr_sparse_mat),intent(inout) :: bcsr -!!$ type(psb_z_csr_sparse_mat),intent(out) :: ccsr -!!$ type(psb_desc_type),intent(in) :: desc_a -!!$ type(psb_desc_type),intent(inout) :: desc_c -!!$ integer(psb_ipk_), intent(out) :: info -!!$ integer(psb_ipk_), intent(in), optional :: data -!!$ ! ...local scalars.... -!!$ integer(psb_ipk_) :: ictxt, np,me -!!$ integer(psb_ipk_) :: ncol, nnz -!!$ type(psb_z_csr_sparse_mat) :: tcsr1 -!!$ logical :: update_desc_c -!!$ integer(psb_ipk_) :: debug_level, debug_unit, err_act -!!$ character(len=20) :: name, ch_err -!!$ -!!$ if(psb_get_errstatus() /= 0) return -!!$ info=psb_success_ -!!$ name='psb_z_p_csr_spspmm' -!!$ call psb_erractionsave(err_act) -!!$ if (psb_errstatus_fatal()) then -!!$ info = psb_err_internal_error_ ; goto 9999 -!!$ end if -!!$ debug_unit = psb_get_debug_unit() -!!$ debug_level = psb_get_debug_level() -!!$ -!!$ ictxt = desc_a%get_context() -!!$ -!!$ call psb_info(ictxt, me, np) -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),': Start' -!!$ -!!$ update_desc_c = desc_c%is_bld() -!!$ -!!$ ! -!!$ ! This is a bit tricky. -!!$ ! DESC_A is the descriptor of (the columns of) A, and therefore -!!$ ! of the rows of B; the columns of B, in the intended usage, span -!!$ ! a different space for which we have DESC_C. -!!$ ! We are gathering the halo rows of B to multiply by A; -!!$ ! now, the columns of B would ideally be kept in -!!$ ! global numbering, so that we can call this repeatedly to accumulate -!!$ ! the product of multiple operators, and convert to local numbering -!!$ ! at the last possible moment. However, this would imply calling -!!$ ! the serial SPSPMM with a matrix B with the GLOBAL number of columns -!!$ ! and this could be very expensive in memory. The solution is to keep B -!!$ ! in local numbering, so that only columns really appearing count, but to -!!$ ! expand the descriptor when gathering the halo, because by performing -!!$ ! the products we are extending the support of the operator; hence -!!$ ! this routine is intended to be called with a temporary descriptor -!!$ ! DESC_C which is in the BUILD state, to allow for such expansion -!!$ ! across multiple products. -!!$ ! The caller will at some later point finalize the descriptor DESC_C. -!!$ ! -!!$ -!!$ ncol = desc_a%get_local_cols() -!!$ call psb_sphalo(bcsr,desc_a,tcsr1,info,& -!!$ & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) -!!$ nnz = tcsr1%get_nzeros() -!!$ if (update_desc_c) then -!!$ call desc_c%indxmap%g2lip_ins(tcsr1%ja(1:nnz),info) -!!$ else -!!$ call desc_c%indxmap%g2lip(tcsr1%ja(1:nnz),info) -!!$ end if -!!$ if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr1) -!!$ if (info == psb_success_) call tcsr1%free() -!!$ if(info /= psb_success_) then -!!$ call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') -!!$ goto 9999 -!!$ end if -!!$ call bcsr%set_ncols(desc_c%get_local_cols()) -!!$ -!!$ -!!$ if (debug_level >= psb_debug_outer_) & -!!$ & write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm 3' -!!$ if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& -!!$ & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() -!!$ call psb_spspmm(acsr,bcsr,ccsr,info) -!!$ -!!$ call psb_erractionrestore(err_act) -!!$ return -!!$ -!!$9999 call psb_error_handler(ictxt,err_act) -!!$ -!!$ return -!!$ -!!$End Subroutine psb_z_par_csr_spspmm +Subroutine psb_z_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) + use psb_base_mod, psb_protect_name => psb_z_par_csr_spspmm + Implicit None + + type(psb_z_csr_sparse_mat),intent(in) :: acsr + type(psb_z_csr_sparse_mat),intent(inout) :: bcsr + type(psb_z_csr_sparse_mat),intent(out) :: ccsr + type(psb_desc_type),intent(in) :: desc_a + type(psb_desc_type),intent(inout) :: desc_c + integer(psb_ipk_), intent(out) :: info + integer(psb_ipk_), intent(in), optional :: data + ! ...local scalars.... + integer(psb_ipk_) :: ictxt, np,me + integer(psb_ipk_) :: ncol, nnz + type(psb_lz_csr_sparse_mat) :: ltcsr + type(psb_z_csr_sparse_mat) :: tcsr + logical :: update_desc_c + integer(psb_ipk_) :: debug_level, debug_unit, err_act + character(len=20) :: name, ch_err + + if(psb_get_errstatus() /= 0) return + info=psb_success_ + name='psb_z_p_csr_spspmm' + call psb_erractionsave(err_act) + if (psb_errstatus_fatal()) then + info = psb_err_internal_error_ ; goto 9999 + end if + debug_unit = psb_get_debug_unit() + debug_level = psb_get_debug_level() + + ictxt = desc_a%get_context() + + call psb_info(ictxt, me, np) + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + update_desc_c = desc_c%is_bld() + + ! + ! This is a bit tricky. + ! DESC_A is the descriptor of (the columns of) A, and therefore + ! of the rows of B; the columns of B, in the intended usage, span + ! a different space for which we have DESC_C. + ! We are gathering the halo rows of B to multiply by A; + ! now, the columns of B would ideally be kept in + ! global numbering, so that we can call this repeatedly to accumulate + ! the product of multiple operators, and convert to local numbering + ! at the last possible moment. However, this would imply calling + ! the serial SPSPMM with a matrix B with the GLOBAL number of columns + ! and this could be very expensive in memory. The solution is to keep B + ! in local numbering, so that only columns really appearing count, but to + ! expand the descriptor when gathering the halo, because by performing + ! the products we are extending the support of the operator; hence + ! this routine is intended to be called with a temporary descriptor + ! DESC_C which is in the BUILD state, to allow for such expansion + ! across multiple products. + ! The caller will at some later point finalize the descriptor DESC_C. + ! + + ncol = desc_a%get_local_cols() + call psb_sphalo(bcsr,desc_a,ltcsr,info,& + & colcnv=.true.,rowscale=.true.,outcol_glob=.true.,col_desc=desc_c,data=data) + nnz = ltcsr%get_nzeros() + if (update_desc_c) then + call desc_c%indxmap%g2lip_ins(ltcsr%ja(1:nnz),info) + else + call desc_c%indxmap%g2lip(ltcsr%ja(1:nnz),info) + end if + call ltcsr%mv_to_ifmt(tcsr,info) + if (info == psb_success_) call psb_rwextd(ncol,bcsr,info,b=tcsr) + if (info == psb_success_) call tcsr%free() + if(info /= psb_success_) then + call psb_errpush(psb_err_internal_error_,name,a_err='Extend am3') + goto 9999 + end if + call bcsr%set_ncols(desc_c%get_local_cols()) + + + if (debug_level >= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm 3' + if (debug_level >= psb_debug_outer_) write(debug_unit,*) me,' ',trim(name),& + & 'starting spspmm ',acsr%get_nrows(),acsr%get_ncols(),bcsr%get_nrows(),bcsr%get_ncols() + call psb_spspmm(acsr,bcsr,ccsr,info) + + call psb_erractionrestore(err_act) + return + +9999 call psb_error_handler(ictxt,err_act) + + return + +End Subroutine psb_z_par_csr_spspmm Subroutine psb_lz_par_csr_spspmm(acsr,desc_a,bcsr,ccsr,desc_c,info,data) use psb_base_mod, psb_protect_name => psb_lz_par_csr_spspmm diff --git a/base/tools/psb_zspasb.f90 b/base/tools/psb_zspasb.f90 index 9db285505..6cdfc61f0 100644 --- a/base/tools/psb_zspasb.f90 +++ b/base/tools/psb_zspasb.f90 @@ -122,11 +122,11 @@ subroutine psb_zspasb(a,desc_a, info, afmt, upd, dupl, mold) end if - IF (debug_level >= psb_debug_ext_) then + if (debug_level >= psb_debug_ext_) then ch_err=a%get_fmt() write(debug_unit, *) me,' ',trim(name),': From SPCNV',& & info,' ',ch_err - end IF + end if if (psb_errstatus_fatal()) then info=psb_err_from_subroutine_ diff --git a/base/tools/psb_zsphalo.F90 b/base/tools/psb_zsphalo.F90 index 6dc1d82b9..0e32938b6 100644 --- a/base/tools/psb_zsphalo.F90 +++ b/base/tools/psb_zsphalo.F90 @@ -31,11 +31,26 @@ ! ! File: psb_zsphalo.f90 ! -! Subroutine: psb_zsphalo +! Subroutine: psb_zsphalo psb_lzsphalo ! This routine does the retrieval of remote matrix rows. -! Note that retrieval is done through GTBLK, therefore it should work -! for any matrix format in A; as for the output, default is CSR. -! +! Retrieval is done through GETROW, therefore it should work +! for any matrix format in A; as for the output, default is CSR. +! +! There is also a specialized version lz_CSR whose interface +! is adapted for the needs of z_par_csr_spspmm. +! +! There are three possible exchange algorithms: +! 1. Use MPI_Alltoallv +! 2. Use psb_simple_a2av +! 3. Use psb_simple_triad_a2av +! Default choice is 3. The MPI variant has proved to be inefficient; +! that is because it is not persistent, therefore you pay the initialization price +! every time, and it is not optimized for a sparse communication pattern, +! most MPI implementations assume that all communications are non-empty. +! The PSB_SIMPLE variants reuse the same communicator, and go for a simplistic +! sequence of sends/receive that is quite efficient for a sparse communication +! pattern. To be refined/reviewed in the future to compare with neighbour +! persistent collectives. ! ! Arguments: ! a - type(psb_zspmat_type) The local part of input matrix A @@ -55,9 +70,6 @@ ! psb_comm_ext_ use ext_index ! psb_comm_ovrl_ DISABLED for this routine. ! -#undef SP_A2AV_MPI -#undef SP_A2AV_XI -#define SP_A2AV_MAT Subroutine psb_zsphalo(a,desc_a,blk,info,rowcnv,colcnv,& & rowscale,colscale,outfmt,data) use psb_base_mod, psb_protect_name => psb_zsphalo @@ -314,16 +326,36 @@ Subroutine psb_zsphalo(a,desc_a,blk,info,rowcnv,colcnv,& call psb_errpush(info,name,a_err=ch_err); goto 9999 end if - - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,iarcv,jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & iarcv,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & jarcv,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& & iarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & jarcv,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -390,16 +422,36 @@ Subroutine psb_zsphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_ipk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_ipk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - ch_err='mpi_alltoallv' + ch_err='alltoallv' call psb_errpush(info,name,a_err=ch_err) goto 9999 end if @@ -506,8 +558,7 @@ Subroutine psb_lzsphalo(a,desc_a,blk,info,rowcnv,colcnv,& integer(psb_ipk_), intent(in), optional :: data ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter, proc, i, & - & n_el_send,n_el_recv,& + integer(psb_ipk_) :: counter, proc, i, n_el_send,n_el_recv, & & n_elem, j, ipx,mat_recv, idxs,idxr,nz,& & data_,totxch,nxs, nxr, ncg integer(psb_lpk_) :: r, k, irmin, irmax, icmin, icmax, iszs, iszr, & @@ -718,16 +769,37 @@ Subroutine psb_lzsphalo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) - call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -829,12 +901,11 @@ Subroutine psb_lz_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& type(psb_desc_type),Intent(in), optional, target :: col_desc ! ...local scalars.... integer(psb_ipk_) :: ictxt, np,me - integer(psb_ipk_) :: counter,proc,i, & - & n_el_send,k,n_el_recv,r,& - & n_elem, j, ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& - & irmin,icmin,data_,totxch,nxs, nxr,& - & err_act, nsnds, nrcvs - integer(psb_lpk_) :: ngtz,irmax,icmax,l1, lnr, lnc, lnnz, ncg, jpx, idx, tot_elem + integer(psb_ipk_) :: counter,proc,i, n_el_send,n_el_recv,& + & n_elem, j,ipx,mat_recv, iszs, iszr,idxs,idxr,nz,& + & data_,totxch,nxs, nxr, err_act, nsnds, nrcvs + integer(psb_lpk_) :: ngtz,irmax,icmax,irmin,icmin,l1, lnr, lnc, lnnz, & + & r, k, ncg, jpx, idx, tot_elem integer(psb_mpk_) :: icomm, minfo integer(psb_mpk_), allocatable :: brvindx(:), & & rvsz(:), bsdindx(:),sdsz(:) @@ -1054,32 +1125,36 @@ Subroutine psb_lz_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& goto 9999 end if -#if defined(SP_A2AV_MPI) - call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& - & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo == mpi_success) & - & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& - & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) - if (minfo /= mpi_success) info = minfo -#elif defined(SP_A2AV_XI) - call lz_my_a2av(valsnd,sdsz,bsdindx,& + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& & acoo%val,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(iasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(iasnd,sdsz,bsdindx,& & acoo%ia,rvsz,brvindx,ictxt,info) - if (info == psb_success_) call i_my_a2av(jasnd,sdsz,bsdindx,& + if (info == psb_success_) call psb_simple_a2av(jasnd,sdsz,bsdindx,& & acoo%ja,rvsz,brvindx,ictxt,info) -#elif defined(SP_A2AV_MAT) - call lz_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ipdxv,ictxt,icomm,info) -#else - choke on me @! -#endif + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(iasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(jasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select + if (info /= psb_success_) then info=psb_err_from_subroutine_ - call psb_errpush(info,name,a_err='mpi_alltoallv') + call psb_errpush(info,name,a_err='alltoallv') goto 9999 end if @@ -1163,185 +1238,376 @@ Subroutine psb_lz_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& return -#if defined(SP_A2AV_XI) || defined(SP_A2AV_MAT) -contains +End Subroutine psb_lz_csr_halo -#if defined(SP_A2AV_MAT) - subroutine lz_coo_my_a2av(valsnd,iasnd,jasnd,sdsz,bsdindx,& - & valrcv,iarcv,jarcv,rvsz,brvindx,ipdxv,ictxt,icomm,info) +Subroutine psb_z_lz_csr_halo(a,desc_a,blk,info,rowcnv,colcnv,& + & rowscale,colscale,data,outcol_glob,col_desc) + use psb_base_mod, psb_protect_name => psb_z_lz_csr_halo #ifdef MPI_MOD - use mpi + use mpi #endif - Implicit None + Implicit None #ifdef MPI_H - include 'mpif.h' + include 'mpif.h' #endif - complex(psb_dpk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(in) :: ipdxv(:) - integer(psb_lpk_), intent(in) :: iasnd(:), jasnd(:) - complex(psb_dpk_), intent(out) :: valrcv(:) - integer(psb_lpk_), intent(out) :: iarcv(:), jarcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_mpk_), intent(in) :: icomm - integer(psb_ipk_), intent(out) :: info - !Local variables - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz, counter - integer(psb_mpk_) :: proc_to_comm, p2ptag, p2pstat(mpi_status_size), iret - integer(psb_mpk_), allocatable :: prcid(:), rvhd(:,:) - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))= psb_debug_outer_) & + & write(debug_unit,*) me,' ',trim(name),': Start' + + if (present(rowcnv)) then + rowcnv_ = rowcnv + else + rowcnv_ = .true. + endif + if (present(colcnv)) then + colcnv_ = colcnv + else + colcnv_ = .true. + endif + if (present(rowscale)) then + rowscale_ = rowscale + else + rowscale_ = .false. + endif + if (present(colscale)) then + colscale_ = colscale + else + colscale_ = .false. + endif + if (present(data)) then + data_ = data + else + data_ = psb_comm_halo_ + endif + if (present(outcol_glob)) then + outcol_glob_ = outcol_glob + else + outcol_glob_ = .false. + endif + if (present(col_desc)) then + col_desc_ => col_desc + else + col_desc_ => desc_a + end if + + Allocate(brvindx(np+1),& + & rvsz(np),sdsz(np),bsdindx(np+1), acoo,stat=info) + + if (info /= psb_success_) then + info=psb_err_alloc_dealloc_ + call psb_errpush(info,name) + goto 9999 + end if + + If (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Data selector',data_ + select case(data_) + case(psb_comm_halo_,psb_comm_ext_ ) + ! Do not accept OVRLAP_INDEX any longer. + case default + call psb_errpush(psb_err_from_subroutine_,name,a_err='wrong Data selector') + goto 9999 + end select - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - p2ptag = psb_dcomplex_swap_tag - call mpi_irecv(valrcv(idx+1:idx+sz),sz,& - & psb_mpi_c_dpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,1),iret) - p2ptag = psb_int_swap_tag - call mpi_irecv(iarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,2),iret) - call mpi_irecv(jarcv(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,rvhd(ip+1,3),iret) - end if - counter = counter+n_el_send+3 + sdsz(:)=0 + rvsz(:)=0 + l1 = 0 + brvindx(1) = 0 + bsdindx(1) = 0 + counter=1 + idx = 0 + idxs = 0 + idxr = 0 + + call desc_a%get_list(data_,pdxv,totxch,nxr,nxs,info) + ipdxv = pdxv%get_vect() + ! For all rows in the halo descriptor, extract the row size + lnr = 0 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + tot_elem = 0 + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + tot_elem = tot_elem+n_elem Enddo + sdsz(proc+1) = tot_elem + lnr = lnr + n_el_recv + counter = counter+n_el_send+3 + Enddo + ! + ! Exchange row sizes, so as to know sends/receives. + ! This is different from the halo exchange because the + ! size of the rows may vary, as opposed to fixed + ! (multi) vector row size. + ! + call mpi_alltoall(sdsz,1,psb_mpi_mpk_,& + & rvsz,1,psb_mpi_mpk_,icomm,minfo) + + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='mpi_alltoall') + goto 9999 + end if + nsnds = count(sdsz /= 0) + nrcvs = count(rvsz /= 0) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done initial alltoall',nsnds,nrcvs - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - if (prcid(ip+1)<0) prcid(ip+1) = psb_get_mpi_rank(ictxt,ip) - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - p2ptag = psb_dcomplex_swap_tag - call mpi_send(valsnd(idx+1:idx+sz),sz,& - & psb_mpi_c_dpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - p2ptag = psb_int_swap_tag - call mpi_send(iasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) - call mpi_send(jasnd(idx+1:idx+sz),sz,& - & psb_mpi_lpk_,prcid(ip+1),& - & p2ptag, icomm,iret) + idxs = 0 + idxr = 0 + counter = 1 + Do + proc=ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + bsdindx(proc+1) = idxs + idxs = idxs + sdsz(proc+1) + brvindx(proc+1) = idxr + idxr = idxr + rvsz(proc+1) + counter = counter+n_el_send+3 + Enddo + + iszr = sum(rvsz) + mat_recv = iszr + iszs = sum(sdsz) + + lnnz = max(iszr,iszs,ione) + lnc = a%get_ncols() + call acoo%allocate(lnr,lnc,lnnz) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Sizes:',acoo%get_size(),& + & ' Send:',sdsz(:),' Receive:',rvsz(:) + + call psb_ensure_size(max(iszs,1),iasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),jasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),liasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),ljasnd,info) + if (info == psb_success_) call psb_ensure_size(max(iszs,1),valsnd,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='ensure_size') + goto 9999 + end if + + l1 = 0 + ipx = 1 + counter=1 + idx = 0 + ! + ! Make sure to get all columns in csget. + ! This is necessary when sphalo is used to compute a transpose, + ! as opposed to just gathering halo for spspmm purposes. + ! + ncg = huge(ncg) + tot_elem = 0 + Do + proc = ipdxv(counter) + if (proc == -1) exit + n_el_recv = ipdxv(counter+psb_n_elem_recv_) + counter = counter+n_el_recv + n_el_send = ipdxv(counter+psb_n_elem_send_) + + Do j=0,n_el_send-1 + idx = ipdxv(counter+psb_elem_send_+j) + n_elem = a%get_nz_row(idx) + call a%csget(idx,idx,ngtz,iasnd,jasnd,valsnd,info,& + & append=.true.,nzin=tot_elem,jmax=ncg) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_sp_getrow') + goto 9999 end if - counter = counter+n_el_send+3 + tot_elem = tot_elem+ngtz Enddo + counter = counter+n_el_send+3 + Enddo + nz = tot_elem - counter=1 - Do - ip=ipdxv(counter) - if (ip == -1) exit - n_el_recv = ipdxv(counter+psb_n_elem_recv_) - counter = counter+n_el_recv - n_el_send = ipdxv(counter+psb_n_elem_send_) - sz = rvsz(ip+1) - if (sz > 0) then - call mpi_wait(rvhd(ip+1,1),p2pstat,iret) - call mpi_wait(rvhd(ip+1,2),p2pstat,iret) - call mpi_wait(rvhd(ip+1,3),p2pstat,iret) - end if - counter = counter+n_el_send+3 - Enddo + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Going for alltoallv',iszs,iszr + if (rowcnv_) then + call psb_loc_to_glob(iasnd(1:nz),liasnd(1:nz),desc_a,info,iact='I') + else + liasnd(1:nz) = iasnd(1:nz) + end if + if (colcnv_) then + call psb_loc_to_glob(jasnd(1:nz),ljasnd(1:nz),col_desc_,info,iact='I') + else + ljasnd(1:nz) = jasnd(1:nz) + end if + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_loc_to_glob') + goto 9999 + end if + select case(psb_get_sp_a2av_alg()) + case(psb_sp_a2av_smpl_triad_) + call psb_simple_triad_a2av(valsnd,liasnd,ljasnd,sdsz,bsdindx,& + & acoo%val,acoo%ia,acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_smpl_v_) + call psb_simple_a2av(valsnd,sdsz,bsdindx,& + & acoo%val,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(liasnd,sdsz,bsdindx,& + & acoo%ia,rvsz,brvindx,ictxt,info) + if (info == psb_success_) call psb_simple_a2av(ljasnd,sdsz,bsdindx,& + & acoo%ja,rvsz,brvindx,ictxt,info) + case(psb_sp_a2av_mpi_) + call mpi_alltoallv(valsnd,sdsz,bsdindx,psb_mpi_c_dpk_,& + & acoo%val,rvsz,brvindx,psb_mpi_c_dpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(liasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ia,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo == mpi_success) & + & call mpi_alltoallv(ljasnd,sdsz,bsdindx,psb_mpi_lpk_,& + & acoo%ja,rvsz,brvindx,psb_mpi_lpk_,icomm,minfo) + if (minfo /= mpi_success) info = minfo + case default + info = psb_err_internal_error_ + call psb_errpush(info,name,a_err='wrong A2AV alg selector') + goto 9999 + end select - end subroutine lz_coo_my_a2av -#endif -#if defined(SP_A2AV_XI) - subroutine lz_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - complex(psb_dpk_), intent(in) :: valsnd(:) - complex(psb_dpk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='alltoallv') + goto 9999 + end if + + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done alltoallv' + ! + ! Convert into local numbering + ! + if (rowcnv_) call psb_glob_to_loc(acoo%ia(1:iszr),desc_a,info,iact='I') + ! + ! This seems to be the correct output condition + ! + if (colcnv_.and.(.not.outcol_glob_)) & + & call psb_glob_to_loc(acoo%ja(1:iszr),col_desc_,info,iact='I') - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psbglob_to_loc') + goto 9999 + end if - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz))0).and.(k>0)) Then + l1=l1+1 + acoo%val(l1) = acoo%val(i) + acoo%ia(l1) = r + acoo%ja(l1) = k + irmin = min(irmin,r) + irmax = max(irmax,r) + icmin = min(icmin,k) + icmax = max(icmax,k) + End If + Enddo + if (rowscale_) then + call acoo%set_nrows(max(irmax-irmin+1,0)) + acoo%ia(1:l1) = acoo%ia(1:l1) - irmin + 1 + else + call acoo%set_nrows(irmax) + end if + if (colscale_) then + call acoo%set_ncols(max(icmax-icmin+1,0)) + acoo%ja(1:l1) = acoo%ja(1:l1) - icmin + 1 + else + call acoo%set_ncols(icmax) + end if - do ip = 0, np-1 - sz = sdsz(ip+1) - if (sz > 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do + call acoo%set_nzeros(l1) + call acoo%set_sorted(.false.) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine lz_my_a2av + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),& + & ': End data exchange',counter,l1 - subroutine i_my_a2av(valsnd,sdsz,bsdindx,& - & valrcv,rvsz,brvindx,ictxt,info) - integer(psb_ipk_), intent(in) :: valsnd(:) - integer(psb_ipk_), intent(out) :: valrcv(:) - integer(psb_mpk_), intent(in) :: bsdindx(:), brvindx(:), sdsz(:), rvsz(:) - integer(psb_ipk_), intent(in) :: ictxt - integer(psb_ipk_), intent(out) :: info - + call acoo%fix(info) + if (info == psb_success_) call acoo%mv_to_fmt(blk,info) + if (info /= psb_success_) then + info=psb_err_from_subroutine_ + call psb_errpush(info,name,a_err='psb_spcnv') + goto 9999 + end if - integer(psb_ipk_) :: iam, np, i,j,k, ip, ipx, idx, sz + Deallocate(brvindx,bsdindx,rvsz,sdsz,& + & iasnd,jasnd,valsnd,stat=info) + if (debug_level >= psb_debug_outer_)& + & write(debug_unit,*) me,' ',trim(name),': Done' - call psb_info(ictxt,iam,np) - if (min(size(bsdindx),size(brvindx),size(sdsz),size(rvsz)) 0) then - idx = bsdindx(ip+1) - call psb_snd(ictxt,valsnd(idx+1:idx+sz),ip) - end if - end do +9999 call psb_error_handler(ictxt,err_act) - do ip = 0, np-1 - sz = rvsz(ip+1) - if (sz > 0) then - idx = brvindx(ip+1) - call psb_rcv(ictxt,valrcv(idx+1:idx+sz),ip) - end if - end do - - end subroutine i_my_a2av -#endif -#endif -End Subroutine psb_lz_csr_halo + return + +End Subroutine psb_z_lz_csr_halo diff --git a/base/tools/psb_zspins.f90 b/base/tools/psb_zspins.F90 similarity index 99% rename from base/tools/psb_zspins.f90 rename to base/tools/psb_zspins.F90 index f7129ce5a..6926bdc05 100644 --- a/base/tools/psb_zspins.f90 +++ b/base/tools/psb_zspins.F90 @@ -288,6 +288,7 @@ subroutine psb_zspins_csr_lirp(nr,irp,ja,val,irw,a,desc_a,info,rebuild,local) end subroutine psb_zspins_csr_lirp +#if defined(IPK4) && defined(LPK8) subroutine psb_zspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) use psb_base_mod, psb_protect_name => psb_zspins_csr_iirp use psi_mod @@ -384,6 +385,7 @@ subroutine psb_zspins_csr_iirp(nr,irw,irp,ja,val,a,desc_a,info,rebuild,local) return end subroutine psb_zspins_csr_iirp +#endif subroutine psb_zspins_2desc(nz,ia,ja,val,a,desc_ar,desc_ac,info) use psb_base_mod, psb_protect_name => psb_zspins_2desc diff --git a/docs/html/index.html b/docs/html/index.html index b53f97f39..0cca7b4cb 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -197,13 +197,13 @@ href="userhtmlsu73.html#x85-1220007.17" id="QQ2-85-150">psb_rcv — Receive
8 Error handling
 8.1 psb_errpush +href="userhtmlsu74.html#x87-1240008.1" id="QQ2-87-154">psb_errpush — Pushes an error code onto the error stack
 8.2 psb_error +href="userhtmlsu75.html#x88-1250008.2" id="QQ2-88-155">psb_error — Prints the error stack content and aborts execution
 8.3 psb_set_errverbosity +href="userhtmlsu76.html#x89-1260008.3" id="QQ2-89-156">psb_set_errverbosity — Sets the verbosity of error messages
 8.4 psb_set_erraction +href="userhtmlsu77.html#x90-1270008.4" id="QQ2-90-157">psb_set_erraction — Set the type of action to be taken upon error condition
9 Utilities
 9.1 psb_rcv — Receive
8
Error handling

 8.1 psb_errpush +href="userhtmlsu74.html#x87-1240008.1" id="QQ2-87-154">psb_errpush — Pushes an error code onto the error stack
 8.2 psb_error +href="userhtmlsu75.html#x88-1250008.2" id="QQ2-88-155">psb_error — Prints the error stack content and aborts execution
 8.3 psb_set_errverbosity +href="userhtmlsu76.html#x89-1260008.3" id="QQ2-89-156">psb_set_errverbosity — Sets the verbosity of error messages
 8.4 psb_set_erraction +href="userhtmlsu77.html#x90-1270008.4" id="QQ2-90-157">psb_set_erraction — Set the type of action to be taken upon error condition
9 Utilities
 9.1 psb_rcv — Receive data
8 Error handling
 8.1 psb_errpush +href="userhtmlsu74.html#x87-1240008.1">psb_errpush — Pushes an error code onto the error stack
 8.2 psb_error +href="userhtmlsu75.html#x88-1250008.2">psb_error — Prints the error stack content and aborts execution
 8.3 psb_set_errverbosity +href="userhtmlsu76.html#x89-1260008.3">psb_set_errverbosity — Sets the verbosity of error messages
 8.4 psb_set_erraction +href="userhtmlsu77.html#x90-1270008.4">psb_set_erraction — Set the type of action to be taken upon error condition
9 Utilities
 9.1 7. >

PIC

Figure 1:

PIC

Figure 2: An integer value that contains an error code. >

PIC


Figure 7: a performs a scaling on the overlap elements >

PIC


Figure 8: -psb_errpush +psb_errpush — Pushes an error code onto the error stack @@ -10,13 +10,12 @@ -