/* --------------------------------------------------------------------- * * -- PBLAS auxiliary routine (version 2.0) -- * University of Tennessee, Knoxville, Oak Ridge National Laboratory, * and University of California, Berkeley. * April 1, 1998 * * --------------------------------------------------------------------- */ /* * Include files */ #include "../pblas.h" #include "../PBpblas.h" #include "../PBtools.h" #include "../PBblacs.h" #include "../PBblas.h" #ifdef __STDC__ int PB_Cg2lrem( int IG, int INB, int NB, int MYPROC, int SRCPROC, int NPROCS ) #else int PB_Cg2lrem( IG, INB, NB, MYPROC, SRCPROC, NPROCS ) /* * .. Scalar Arguments .. */ int IG, INB, NB, NPROCS, MYPROC, SRCPROC; #endif { /* * Purpose * ======= * * PB_Cg2lrem computes the local index of a matrix entry pointed to by * the global index IG. Note that when MYPROC is not the process owning * this entry, this routine returns the closest larger local index cor- * responding to IG just like the routine PB_Cinfog2l. * * Arguments * ========= * * IG (global input) INTEGER * On entry, IG specifies the global index of the matrix entry. * IG must be at least zero. * * INB (global input) INTEGER * On entry, INB specifies the size of the first block of the * global matrix. INB must be at least one. * * NB (global input) INTEGER * On entry, NB specifies the size of the blocks used to parti- * tion the matrix. NB must be at least one. * * MYPROC (global input) INTEGER * On entry, MYPROC specifies the process number in which the * value of the local index is to be computed. MYPROC must be at * least zero and strictly less than NPROCS. * * SRCPROC (global input) INTEGER * On entry, if SRCPROC = -1, the data is not distributed but * replicated, in which case this routine returns IG in all * processes. Otherwise, the value of SRCPROC is ignored. * * NPROCS (global input) INTEGER * On entry, NPROCS specifies the total number of process rows * or columns over which the matrix is distributed. NPROCS must * be at least one. * * -- Written on April 1, 1998 by * Antoine Petitet, University of Tennessee, Knoxville 37996, USA. * * --------------------------------------------------------------------- */ /* * .. Local Scalars .. */ int ilocblk, mydist, nblocks, proc; /* .. * .. Executable Statements .. * */ /* * The data is not distributed, or there is just one process in this dimension * of the grid. */ if( ( SRCPROC == -1 ) || ( NPROCS == 1 ) ) return( IG ); /* * IG refers to an entry in the first block */ if( IG < INB ) return( ( MYPROC == SRCPROC ? IG : 0 ) ); /* * The discussion goes as follows: compute my distance from the source process * so that within this process coordinate system, the source process is the * process such that mydist = 0, or equivalently MYROC == SRCPROC. * * Find out the global coordinate of the block IG belongs to (nblocks), as well * as the minimum local number of blocks that every process has. * * when mydist < nblocks - ilocblk * NPROCS, I own ilocblk + 1 full blocks, * when mydist > nblocks - ilocblk * NPROCS, I own ilocblk full blocks, * when mydist = nblocks - ilocblk * NPROCS, I own ilocblk full blocks * but not IG, or I own ilocblk + 1 blocks and the entry IG refers to. */ if( MYPROC == SRCPROC ) { /* * If I am the source process and there are less than NPROCS blocks, then * the local index in that process is INB. */ nblocks = ( IG - INB ) / NB + 1; if( nblocks < NPROCS ) return( INB ); /* * IG refers to an entry that is not in the first block, find out which process * has it. */ proc = SRCPROC + nblocks; proc -= ( proc / NPROCS ) * NPROCS; /* * Since mydist = 0 and nblocks - ilocblk * NPROCS >= 0, there are only three * possible cases: * * 1) When 0 = mydist = nblocks - ilocblk * NPROCS = 0 and I don't own IG, in * which case II = INB + ( ilocblk - 1 ) * NB. Note that this case cannot * happen when ilocblk is zero, since nblocks is at least one. * * 2) When 0 = mydist = nblocks - ilocblk * NPROCS = 0 and I own IG, in which * case IG and II can respectively be written as INB + (nblocks-1)*NB + IL, * INB + (ilocblk-1) * NB + IL. That is II = IG + ( ilocblk - nblocks )*NB. * Note that this case cannot happen when ilocblk is zero, since nblocks * is at least one. * * 3) mydist = 0 < nblocks - ilocblk * NPROCS, the source process owns * ilocblk+1 full blocks, and therefore II = INB + ilocblk * NB. Note * that when ilocblk is zero, II is just INB. */ ilocblk = nblocks / NPROCS; if( ilocblk * NPROCS >= nblocks ) return( ( ( MYPROC == proc ) ? IG + ( ilocblk - nblocks ) * NB : INB + ( ilocblk - 1 ) * NB ) ); else return( INB + ilocblk * NB ); } else { /* * IG refers to an entry that is not in the first block, find out which process * has it. */ nblocks = ( IG -= INB ) / NB + 1; proc = SRCPROC + nblocks; proc -= ( proc / NPROCS ) * NPROCS; /* * Compute my distance from the source process so that within this process * coordinate system, the source process is the process such that mydist=0. */ if( ( mydist = MYPROC - SRCPROC ) < 0 ) mydist += NPROCS; /* * When mydist < nblocks - ilocblk * NPROCS, I own ilocblk + 1 full blocks of * size NB since I am not the source process, i.e. II = ( ilocblk + 1 ) * NB. * When mydist >= nblocks - ilocblk * NPROCS and I don't own IG, I own ilocblk * full blocks of size NB, i.e. II = ilocblk * NB, otherwise I own ilocblk * blocks and IG, in which case IG can be written as INB + (nblocks-1)*NB + IL * and II = ilocblk*NB + IL = IG - INB + ( ilocblk - nblocks + 1 )*NB. */ if( nblocks < NPROCS ) { mydist -= nblocks; return( ( ( mydist < 0 ) ? NB : ( ( MYPROC == proc ) ? IG + ( 1 - nblocks ) * NB : 0 ) ) ); } else { ilocblk = nblocks / NPROCS; mydist -= nblocks - ilocblk * NPROCS; return( ( ( mydist < 0 ) ? ( ilocblk + 1 ) * NB : ( ( MYPROC == proc ) ? ( ilocblk - nblocks + 1 ) * NB + IG : ilocblk * NB ) ) ); } } /* * End of PB_Cg2lrem */ }