16618991cSMark Adams /* 26618991cSMark Adams GAMG geometric-algebric multigrid PC - Mark Adams 2011 36618991cSMark Adams */ 46618991cSMark Adams #include <petsc/private/matimpl.h> 56618991cSMark Adams #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/ 66618991cSMark Adams #include <petsc/private/kspimpl.h> 76618991cSMark Adams 86618991cSMark Adams #undef __FUNCT__ 96618991cSMark Adams #define __FUNCT__ "MatCollapseRow" 106618991cSMark Adams /* 116618991cSMark Adams Produces a set of block column indices of the matrix row, one for each block represented in the original row 126618991cSMark Adams 136618991cSMark Adams n - the number of block indices in cc[] 146618991cSMark Adams cc - the block indices (must be large enough to contain the indices) 156618991cSMark Adams */ 166618991cSMark Adams PETSC_STATIC_INLINE PetscErrorCode MatCollapseRow(Mat Amat,PetscInt row,PetscInt bs,PetscInt *n,PetscInt *cc) 176618991cSMark Adams { 186618991cSMark Adams PetscInt cnt = -1,nidx,j; 196618991cSMark Adams const PetscInt *idx; 206618991cSMark Adams PetscErrorCode ierr; 216618991cSMark Adams 226618991cSMark Adams PetscFunctionBegin; 236618991cSMark Adams ierr = MatGetRow(Amat,row,&nidx,&idx,NULL);CHKERRQ(ierr); 246618991cSMark Adams if (nidx) { 256618991cSMark Adams cnt = 0; 266618991cSMark Adams cc[cnt] = idx[0]/bs; 276618991cSMark Adams for (j=1; j<nidx; j++) { 286618991cSMark Adams if (cc[cnt] < idx[j]/bs) cc[++cnt] = idx[j]/bs; 296618991cSMark Adams } 306618991cSMark Adams } 316618991cSMark Adams ierr = MatRestoreRow(Amat,row,&nidx,&idx,NULL);CHKERRQ(ierr); 326618991cSMark Adams *n = cnt+1; 336618991cSMark Adams PetscFunctionReturn(0); 346618991cSMark Adams } 356618991cSMark Adams 366618991cSMark Adams #undef __FUNCT__ 376618991cSMark Adams #define __FUNCT__ "MatCollapseRows" 386618991cSMark Adams /* 396618991cSMark Adams Produces a set of block column indices of the matrix block row, one for each block represented in the original set of rows 406618991cSMark Adams 416618991cSMark Adams ncollapsed - the number of block indices 426618991cSMark Adams collapsed - the block indices (must be large enough to contain the indices) 436618991cSMark Adams */ 446618991cSMark Adams PETSC_STATIC_INLINE PetscErrorCode MatCollapseRows(Mat Amat,PetscInt start,PetscInt bs,PetscInt *w0,PetscInt *w1,PetscInt *w2,PetscInt *ncollapsed,PetscInt **collapsed) 456618991cSMark Adams { 466618991cSMark Adams PetscInt i,nprev,*cprev = w0,ncur = 0,*ccur = w1,*merged = w2,*cprevtmp; 476618991cSMark Adams PetscErrorCode ierr; 486618991cSMark Adams 496618991cSMark Adams PetscFunctionBegin; 506618991cSMark Adams ierr = MatCollapseRow(Amat,start,bs,&nprev,cprev);CHKERRQ(ierr); 516618991cSMark Adams for (i=start+1; i<start+bs; i++) { 526618991cSMark Adams ierr = MatCollapseRow(Amat,i,bs,&ncur,ccur);CHKERRQ(ierr); 536618991cSMark Adams ierr = PetscMergeIntArray(nprev,cprev,ncur,ccur,&nprev,&merged);CHKERRQ(ierr); 546618991cSMark Adams cprevtmp = cprev; cprev = merged; merged = cprevtmp; 556618991cSMark Adams } 566618991cSMark Adams *ncollapsed = nprev; 576618991cSMark Adams if (collapsed) *collapsed = cprev; 586618991cSMark Adams PetscFunctionReturn(0); 596618991cSMark Adams } 606618991cSMark Adams 616618991cSMark Adams 626618991cSMark Adams /* -------------------------------------------------------------------------- */ 636618991cSMark Adams /* 646618991cSMark Adams PCGAMGCreateGraph - create simple scaled scalar graph from matrix 656618991cSMark Adams 666618991cSMark Adams Input Parameter: 676618991cSMark Adams . Amat - matrix 686618991cSMark Adams Output Parameter: 696618991cSMark Adams . a_Gmaat - eoutput scalar graph (symmetric?) 706618991cSMark Adams */ 716618991cSMark Adams #undef __FUNCT__ 726618991cSMark Adams #define __FUNCT__ "PCGAMGCreateGraph" 736618991cSMark Adams PetscErrorCode PCGAMGCreateGraph(Mat Amat, Mat *a_Gmat) 746618991cSMark Adams { 756618991cSMark Adams PetscErrorCode ierr; 766618991cSMark Adams PetscInt Istart,Iend,Ii,i,jj,kk,ncols,nloc,NN,MM,bs; 776618991cSMark Adams MPI_Comm comm; 786618991cSMark Adams Mat Gmat; 796618991cSMark Adams MatType mtype; 806618991cSMark Adams 816618991cSMark Adams PetscFunctionBegin; 826618991cSMark Adams ierr = PetscObjectGetComm((PetscObject)Amat,&comm);CHKERRQ(ierr); 836618991cSMark Adams ierr = MatGetOwnershipRange(Amat, &Istart, &Iend);CHKERRQ(ierr); 846618991cSMark Adams ierr = MatGetSize(Amat, &MM, &NN);CHKERRQ(ierr); 856618991cSMark Adams ierr = MatGetBlockSize(Amat, &bs);CHKERRQ(ierr); 866618991cSMark Adams nloc = (Iend-Istart)/bs; 876618991cSMark Adams 886618991cSMark Adams #if defined PETSC_GAMG_USE_LOG 896618991cSMark Adams ierr = PetscLogEventBegin(petsc_gamg_setup_events[GRAPH],0,0,0,0);CHKERRQ(ierr); 906618991cSMark Adams #endif 916618991cSMark Adams 926618991cSMark Adams if (bs > 1) { 936618991cSMark Adams const PetscScalar *vals; 946618991cSMark Adams const PetscInt *idx; 956618991cSMark Adams PetscInt *d_nnz, *o_nnz,*blockmask = NULL,maskcnt,*w0,*w1,*w2; 966618991cSMark Adams PetscBool ismpiaij,isseqaij; 976618991cSMark Adams 986618991cSMark Adams /* 996618991cSMark Adams Determine the preallocation needed for the scalar matrix derived from the vector matrix. 1006618991cSMark Adams */ 1016618991cSMark Adams 1026618991cSMark Adams ierr = PetscObjectTypeCompare((PetscObject)Amat,MATSEQAIJ,&isseqaij);CHKERRQ(ierr); 1036618991cSMark Adams ierr = PetscObjectTypeCompare((PetscObject)Amat,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr); 1046618991cSMark Adams 1056618991cSMark Adams ierr = PetscMalloc2(nloc, &d_nnz,isseqaij ? 0 : nloc, &o_nnz);CHKERRQ(ierr); 1066618991cSMark Adams 1076618991cSMark Adams if (isseqaij) { 1086618991cSMark Adams PetscInt max_d_nnz; 1096618991cSMark Adams 1106618991cSMark Adams /* 1116618991cSMark Adams Determine exact preallocation count for (sequential) scalar matrix 1126618991cSMark Adams */ 1136618991cSMark Adams ierr = MatSeqAIJGetMaxRowNonzeros(Amat,&max_d_nnz);CHKERRQ(ierr); 1146618991cSMark Adams max_d_nnz = PetscMin(nloc,bs*max_d_nnz);CHKERRQ(ierr); 1156618991cSMark Adams ierr = PetscMalloc3(max_d_nnz, &w0,max_d_nnz, &w1,max_d_nnz, &w2);CHKERRQ(ierr); 1166618991cSMark Adams for (Ii = 0, jj = 0; Ii < Iend; Ii += bs, jj++) { 1176618991cSMark Adams ierr = MatCollapseRows(Amat,Ii,bs,w0,w1,w2,&d_nnz[jj],NULL);CHKERRQ(ierr); 1186618991cSMark Adams } 1196618991cSMark Adams ierr = PetscFree3(w0,w1,w2);CHKERRQ(ierr); 1206618991cSMark Adams 1216618991cSMark Adams } else if (ismpiaij) { 1226618991cSMark Adams Mat Daij,Oaij; 1236618991cSMark Adams const PetscInt *garray; 1246618991cSMark Adams PetscInt max_d_nnz; 1256618991cSMark Adams 1266618991cSMark Adams ierr = MatMPIAIJGetSeqAIJ(Amat,&Daij,&Oaij,&garray);CHKERRQ(ierr); 1276618991cSMark Adams 1286618991cSMark Adams /* 1296618991cSMark Adams Determine exact preallocation count for diagonal block portion of scalar matrix 1306618991cSMark Adams */ 1316618991cSMark Adams ierr = MatSeqAIJGetMaxRowNonzeros(Daij,&max_d_nnz);CHKERRQ(ierr); 1326618991cSMark Adams max_d_nnz = PetscMin(nloc,bs*max_d_nnz);CHKERRQ(ierr); 1336618991cSMark Adams ierr = PetscMalloc3(max_d_nnz, &w0,max_d_nnz, &w1,max_d_nnz, &w2);CHKERRQ(ierr); 1346618991cSMark Adams for (Ii = 0, jj = 0; Ii < Iend - Istart; Ii += bs, jj++) { 1356618991cSMark Adams ierr = MatCollapseRows(Daij,Ii,bs,w0,w1,w2,&d_nnz[jj],NULL);CHKERRQ(ierr); 1366618991cSMark Adams } 1376618991cSMark Adams ierr = PetscFree3(w0,w1,w2);CHKERRQ(ierr); 1386618991cSMark Adams 1396618991cSMark Adams /* 1406618991cSMark Adams Over estimate (usually grossly over), preallocation count for off-diagonal portion of scalar matrix 1416618991cSMark Adams */ 1426618991cSMark Adams for (Ii = 0, jj = 0; Ii < Iend - Istart; Ii += bs, jj++) { 1436618991cSMark Adams o_nnz[jj] = 0; 1446618991cSMark Adams for (kk=0; kk<bs; kk++) { /* rows that get collapsed to a single row */ 1456618991cSMark Adams ierr = MatGetRow(Oaij,Ii+kk,&ncols,0,0);CHKERRQ(ierr); 1466618991cSMark Adams o_nnz[jj] += ncols; 1476618991cSMark Adams ierr = MatRestoreRow(Oaij,Ii+kk,&ncols,0,0);CHKERRQ(ierr); 1486618991cSMark Adams } 1496618991cSMark Adams if (o_nnz[jj] > (NN/bs-nloc)) o_nnz[jj] = NN/bs-nloc; 1506618991cSMark Adams } 1516618991cSMark Adams 1526618991cSMark Adams } else { 1536618991cSMark Adams /* 1546618991cSMark Adams 1556618991cSMark Adams This is O(nloc*nloc/bs) work! 1566618991cSMark Adams 1576618991cSMark Adams This is accurate for the "diagonal" block of the matrix but will be grossly high for the 1586618991cSMark Adams off diagonal block most of the time but could be too low for the off-diagonal. 1596618991cSMark Adams 1606618991cSMark Adams This should be fixed to be accurate for the off-diagonal portion. Cannot just use a mask 1616618991cSMark Adams for the off-diagonal portion since for huge matrices that would require too much memory per 1626618991cSMark Adams MPI process. 1636618991cSMark Adams */ 1646618991cSMark Adams ierr = PetscMalloc1(nloc, &blockmask);CHKERRQ(ierr); 1656618991cSMark Adams for (Ii = Istart, jj = 0; Ii < Iend; Ii += bs, jj++) { 1666618991cSMark Adams o_nnz[jj] = 0; 1676618991cSMark Adams ierr = PetscMemzero(blockmask,nloc*sizeof(PetscInt));CHKERRQ(ierr); 1686618991cSMark Adams for (kk=0; kk<bs; kk++) { /* rows that get collapsed to a single row */ 1696618991cSMark Adams ierr = MatGetRow(Amat,Ii+kk,&ncols,&idx,0);CHKERRQ(ierr); 1706618991cSMark Adams for (i=0; i<ncols; i++) { 1716618991cSMark Adams if (idx[i] >= Istart && idx[i] < Iend) { 1726618991cSMark Adams blockmask[(idx[i] - Istart)/bs] = 1; 1736618991cSMark Adams } 1746618991cSMark Adams } 1756618991cSMark Adams if (ncols > o_nnz[jj]) { 1766618991cSMark Adams o_nnz[jj] = ncols; 1776618991cSMark Adams if (o_nnz[jj] > (NN/bs-nloc)) o_nnz[jj] = NN/bs-nloc; 1786618991cSMark Adams } 1796618991cSMark Adams ierr = MatRestoreRow(Amat,Ii+kk,&ncols,&idx,0);CHKERRQ(ierr); 1806618991cSMark Adams } 1816618991cSMark Adams maskcnt = 0; 1826618991cSMark Adams for (i=0; i<nloc; i++) { 1836618991cSMark Adams if (blockmask[i]) maskcnt++; 1846618991cSMark Adams } 1856618991cSMark Adams d_nnz[jj] = maskcnt; 1866618991cSMark Adams } 1876618991cSMark Adams ierr = PetscFree(blockmask);CHKERRQ(ierr); 1886618991cSMark Adams } 1896618991cSMark Adams 1906618991cSMark Adams /* get scalar copy (norms) of matrix -- AIJ specific!!! */ 1916618991cSMark Adams ierr = MatGetType(Amat,&mtype);CHKERRQ(ierr); 1926618991cSMark Adams ierr = MatCreate(comm, &Gmat);CHKERRQ(ierr); 1936618991cSMark Adams ierr = MatSetSizes(Gmat,nloc,nloc,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr); 1946618991cSMark Adams ierr = MatSetBlockSizes(Gmat, 1, 1);CHKERRQ(ierr); 1956618991cSMark Adams ierr = MatSetType(Gmat, mtype);CHKERRQ(ierr); 1966618991cSMark Adams ierr = MatSeqAIJSetPreallocation(Gmat,0,d_nnz);CHKERRQ(ierr); 1976618991cSMark Adams ierr = MatMPIAIJSetPreallocation(Gmat,0,d_nnz,0,o_nnz);CHKERRQ(ierr); 1986618991cSMark Adams ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr); 1996618991cSMark Adams 2006618991cSMark Adams for (Ii = Istart; Ii < Iend; Ii++) { 2016618991cSMark Adams PetscInt dest_row = Ii/bs; 2026618991cSMark Adams ierr = MatGetRow(Amat,Ii,&ncols,&idx,&vals);CHKERRQ(ierr); 2036618991cSMark Adams for (jj=0; jj<ncols; jj++) { 2046618991cSMark Adams PetscInt dest_col = idx[jj]/bs; 2056618991cSMark Adams PetscScalar sv = PetscAbs(PetscRealPart(vals[jj])); 2066618991cSMark Adams ierr = MatSetValues(Gmat,1,&dest_row,1,&dest_col,&sv,ADD_VALUES);CHKERRQ(ierr); 2076618991cSMark Adams } 2086618991cSMark Adams ierr = MatRestoreRow(Amat,Ii,&ncols,&idx,&vals);CHKERRQ(ierr); 2096618991cSMark Adams } 2106618991cSMark Adams ierr = MatAssemblyBegin(Gmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2116618991cSMark Adams ierr = MatAssemblyEnd(Gmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2126618991cSMark Adams } else { 2136618991cSMark Adams /* just copy scalar matrix - abs() not taken here but scaled later */ 2146618991cSMark Adams ierr = MatDuplicate(Amat, MAT_COPY_VALUES, &Gmat);CHKERRQ(ierr); 2156618991cSMark Adams } 2166618991cSMark Adams 2176618991cSMark Adams #if defined PETSC_GAMG_USE_LOG 2186618991cSMark Adams ierr = PetscLogEventEnd(petsc_gamg_setup_events[GRAPH],0,0,0,0);CHKERRQ(ierr); 2196618991cSMark Adams #endif 2206618991cSMark Adams 2216618991cSMark Adams *a_Gmat = Gmat; 2226618991cSMark Adams PetscFunctionReturn(0); 2236618991cSMark Adams } 2246618991cSMark Adams 2256618991cSMark Adams /* -------------------------------------------------------------------------- */ 2266618991cSMark Adams /* 2276618991cSMark Adams PCGAMGFilterGraph - filter (remove zero and possibly small values from the) graph and symetrize if needed 2286618991cSMark Adams 2296618991cSMark Adams Input Parameter: 2306618991cSMark Adams . vfilter - threshold paramter [0,1) 2316618991cSMark Adams . symm - symetrize? 2326618991cSMark Adams In/Output Parameter: 2336618991cSMark Adams . a_Gmat - original graph 2346618991cSMark Adams */ 2356618991cSMark Adams #undef __FUNCT__ 2366618991cSMark Adams #define __FUNCT__ "PCGAMGFilterGraph" 2376618991cSMark Adams PetscErrorCode PCGAMGFilterGraph(Mat *a_Gmat,PetscReal vfilter,PetscBool symm) 2386618991cSMark Adams { 2396618991cSMark Adams PetscErrorCode ierr; 2406618991cSMark Adams PetscInt Istart,Iend,Ii,jj,ncols,nnz0,nnz1, NN, MM, nloc; 2416618991cSMark Adams PetscMPIInt rank; 2426618991cSMark Adams Mat Gmat = *a_Gmat, tGmat, matTrans; 2436618991cSMark Adams MPI_Comm comm; 2446618991cSMark Adams const PetscScalar *vals; 2456618991cSMark Adams const PetscInt *idx; 2466618991cSMark Adams PetscInt *d_nnz, *o_nnz; 2476618991cSMark Adams Vec diag; 2486618991cSMark Adams MatType mtype; 2496618991cSMark Adams 2506618991cSMark Adams PetscFunctionBegin; 2516618991cSMark Adams #if defined PETSC_GAMG_USE_LOG 2526618991cSMark Adams ierr = PetscLogEventBegin(petsc_gamg_setup_events[GRAPH],0,0,0,0);CHKERRQ(ierr); 2536618991cSMark Adams #endif 2546618991cSMark Adams /* scale Gmat for all values between -1 and 1 */ 2556618991cSMark Adams ierr = MatCreateVecs(Gmat, &diag, 0);CHKERRQ(ierr); 2566618991cSMark Adams ierr = MatGetDiagonal(Gmat, diag);CHKERRQ(ierr); 2576618991cSMark Adams ierr = VecReciprocal(diag);CHKERRQ(ierr); 2586618991cSMark Adams ierr = VecSqrtAbs(diag);CHKERRQ(ierr); 2596618991cSMark Adams ierr = MatDiagonalScale(Gmat, diag, diag);CHKERRQ(ierr); 2606618991cSMark Adams ierr = VecDestroy(&diag);CHKERRQ(ierr); 2616618991cSMark Adams 2626618991cSMark Adams if (vfilter < 0.0 && !symm) { 2636618991cSMark Adams /* Just use the provided matrix as the graph but make all values positive */ 2646618991cSMark Adams Mat_MPIAIJ *aij = (Mat_MPIAIJ*)Gmat->data; 2656618991cSMark Adams MatInfo info; 2666618991cSMark Adams PetscScalar *avals; 2676618991cSMark Adams PetscMPIInt size; 2686618991cSMark Adams 2696618991cSMark Adams ierr = MPI_Comm_size(PetscObjectComm((PetscObject)Gmat),&size);CHKERRQ(ierr); 2706618991cSMark Adams if (size == 1) { 2716618991cSMark Adams ierr = MatGetInfo(Gmat,MAT_LOCAL,&info);CHKERRQ(ierr); 2726618991cSMark Adams ierr = MatSeqAIJGetArray(Gmat,&avals);CHKERRQ(ierr); 2736618991cSMark Adams for (jj = 0; jj<info.nz_used; jj++) avals[jj] = PetscAbsScalar(avals[jj]); 2746618991cSMark Adams ierr = MatSeqAIJRestoreArray(Gmat,&avals);CHKERRQ(ierr); 2756618991cSMark Adams } else { 2766618991cSMark Adams ierr = MatGetInfo(aij->A,MAT_LOCAL,&info);CHKERRQ(ierr); 2776618991cSMark Adams ierr = MatSeqAIJGetArray(aij->A,&avals);CHKERRQ(ierr); 2786618991cSMark Adams for (jj = 0; jj<info.nz_used; jj++) avals[jj] = PetscAbsScalar(avals[jj]); 2796618991cSMark Adams ierr = MatSeqAIJRestoreArray(aij->A,&avals);CHKERRQ(ierr); 2806618991cSMark Adams ierr = MatGetInfo(aij->B,MAT_LOCAL,&info);CHKERRQ(ierr); 2816618991cSMark Adams ierr = MatSeqAIJGetArray(aij->B,&avals);CHKERRQ(ierr); 2826618991cSMark Adams for (jj = 0; jj<info.nz_used; jj++) avals[jj] = PetscAbsScalar(avals[jj]); 2836618991cSMark Adams ierr = MatSeqAIJRestoreArray(aij->B,&avals);CHKERRQ(ierr); 2846618991cSMark Adams } 2856618991cSMark Adams #if defined PETSC_GAMG_USE_LOG 2866618991cSMark Adams ierr = PetscLogEventEnd(petsc_gamg_setup_events[GRAPH],0,0,0,0);CHKERRQ(ierr); 2876618991cSMark Adams #endif 2886618991cSMark Adams PetscFunctionReturn(0); 2896618991cSMark Adams } 2906618991cSMark Adams 2916618991cSMark Adams ierr = PetscObjectGetComm((PetscObject)Gmat,&comm);CHKERRQ(ierr); 2926618991cSMark Adams ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 2936618991cSMark Adams ierr = MatGetOwnershipRange(Gmat, &Istart, &Iend);CHKERRQ(ierr); 2946618991cSMark Adams nloc = Iend - Istart; 2956618991cSMark Adams ierr = MatGetSize(Gmat, &MM, &NN);CHKERRQ(ierr); 2966618991cSMark Adams 2976618991cSMark Adams if (symm) { 2986618991cSMark Adams ierr = MatTranspose(Gmat, MAT_INITIAL_MATRIX, &matTrans);CHKERRQ(ierr); 2996618991cSMark Adams } 3006618991cSMark Adams 3016618991cSMark Adams /* Determine upper bound on nonzeros needed in new filtered matrix */ 3026618991cSMark Adams ierr = PetscMalloc2(nloc, &d_nnz,nloc, &o_nnz);CHKERRQ(ierr); 3036618991cSMark Adams for (Ii = Istart, jj = 0; Ii < Iend; Ii++, jj++) { 3046618991cSMark Adams ierr = MatGetRow(Gmat,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 3056618991cSMark Adams d_nnz[jj] = ncols; 3066618991cSMark Adams o_nnz[jj] = ncols; 3076618991cSMark Adams ierr = MatRestoreRow(Gmat,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 3086618991cSMark Adams if (symm) { 3096618991cSMark Adams ierr = MatGetRow(matTrans,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 3106618991cSMark Adams d_nnz[jj] += ncols; 3116618991cSMark Adams o_nnz[jj] += ncols; 3126618991cSMark Adams ierr = MatRestoreRow(matTrans,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 3136618991cSMark Adams } 3146618991cSMark Adams if (d_nnz[jj] > nloc) d_nnz[jj] = nloc; 3156618991cSMark Adams if (o_nnz[jj] > (MM-nloc)) o_nnz[jj] = MM - nloc; 3166618991cSMark Adams } 3176618991cSMark Adams ierr = MatGetType(Gmat,&mtype);CHKERRQ(ierr); 3186618991cSMark Adams ierr = MatCreate(comm, &tGmat);CHKERRQ(ierr); 3196618991cSMark Adams ierr = MatSetSizes(tGmat,nloc,nloc,MM,MM);CHKERRQ(ierr); 3206618991cSMark Adams ierr = MatSetBlockSizes(tGmat, 1, 1);CHKERRQ(ierr); 3216618991cSMark Adams ierr = MatSetType(tGmat, mtype);CHKERRQ(ierr); 3226618991cSMark Adams ierr = MatSeqAIJSetPreallocation(tGmat,0,d_nnz);CHKERRQ(ierr); 3236618991cSMark Adams ierr = MatMPIAIJSetPreallocation(tGmat,0,d_nnz,0,o_nnz);CHKERRQ(ierr); 3246618991cSMark Adams ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr); 3256618991cSMark Adams if (symm) { 3266618991cSMark Adams ierr = MatDestroy(&matTrans);CHKERRQ(ierr); 3276618991cSMark Adams } else { 3286618991cSMark Adams /* all entries are generated locally so MatAssembly will be slightly faster for large process counts */ 3296618991cSMark Adams ierr = MatSetOption(tGmat,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr); 3306618991cSMark Adams } 3316618991cSMark Adams 3326618991cSMark Adams for (Ii = Istart, nnz0 = nnz1 = 0; Ii < Iend; Ii++) { 3336618991cSMark Adams ierr = MatGetRow(Gmat,Ii,&ncols,&idx,&vals);CHKERRQ(ierr); 3346618991cSMark Adams for (jj=0; jj<ncols; jj++,nnz0++) { 3356618991cSMark Adams PetscScalar sv = PetscAbs(PetscRealPart(vals[jj])); 3366618991cSMark Adams if (PetscRealPart(sv) > vfilter) { 3376618991cSMark Adams nnz1++; 3386618991cSMark Adams if (symm) { 3396618991cSMark Adams sv *= 0.5; 3406618991cSMark Adams ierr = MatSetValues(tGmat,1,&Ii,1,&idx[jj],&sv,ADD_VALUES);CHKERRQ(ierr); 3416618991cSMark Adams ierr = MatSetValues(tGmat,1,&idx[jj],1,&Ii,&sv,ADD_VALUES);CHKERRQ(ierr); 3426618991cSMark Adams } else { 3436618991cSMark Adams ierr = MatSetValues(tGmat,1,&Ii,1,&idx[jj],&sv,ADD_VALUES);CHKERRQ(ierr); 3446618991cSMark Adams } 3456618991cSMark Adams } 3466618991cSMark Adams } 3476618991cSMark Adams ierr = MatRestoreRow(Gmat,Ii,&ncols,&idx,&vals);CHKERRQ(ierr); 3486618991cSMark Adams } 3496618991cSMark Adams ierr = MatAssemblyBegin(tGmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3506618991cSMark Adams ierr = MatAssemblyEnd(tGmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3516618991cSMark Adams 3526618991cSMark Adams #if defined PETSC_GAMG_USE_LOG 3536618991cSMark Adams ierr = PetscLogEventEnd(petsc_gamg_setup_events[GRAPH],0,0,0,0);CHKERRQ(ierr); 3546618991cSMark Adams #endif 3556618991cSMark Adams 3566618991cSMark Adams #if defined(PETSC_USE_INFO) 3576618991cSMark Adams { 3586618991cSMark Adams double t1 = (!nnz0) ? 1. : 100.*(double)nnz1/(double)nnz0, t2 = (!nloc) ? 1. : (double)nnz0/(double)nloc; 3596618991cSMark Adams ierr = PetscInfo4(*a_Gmat,"\t %g%% nnz after filtering, with threshold %g, %g nnz ave. (N=%D)\n",t1,vfilter,t2,MM);CHKERRQ(ierr); 3606618991cSMark Adams } 3616618991cSMark Adams #endif 3626618991cSMark Adams ierr = MatDestroy(&Gmat);CHKERRQ(ierr); 3636618991cSMark Adams *a_Gmat = tGmat; 3646618991cSMark Adams PetscFunctionReturn(0); 3656618991cSMark Adams } 3666618991cSMark Adams 3676618991cSMark Adams /* -------------------------------------------------------------------------- */ 3686618991cSMark Adams /* 3696618991cSMark Adams PCGAMGGetDataWithGhosts - hacks into Mat MPIAIJ so this must have > 1 pe 3706618991cSMark Adams 3716618991cSMark Adams Input Parameter: 3726618991cSMark Adams . Gmat - MPIAIJ matrix for scattters 3736618991cSMark Adams . data_sz - number of data terms per node (# cols in output) 3746618991cSMark Adams . data_in[nloc*data_sz] - column oriented data 3756618991cSMark Adams Output Parameter: 3766618991cSMark Adams . a_stride - numbrt of rows of output 3776618991cSMark Adams . a_data_out[stride*data_sz] - output data with ghosts 3786618991cSMark Adams */ 3796618991cSMark Adams #undef __FUNCT__ 3806618991cSMark Adams #define __FUNCT__ "PCGAMGGetDataWithGhosts" 3816618991cSMark Adams PetscErrorCode PCGAMGGetDataWithGhosts(Mat Gmat,PetscInt data_sz,PetscReal data_in[],PetscInt *a_stride,PetscReal **a_data_out) 3826618991cSMark Adams { 3836618991cSMark Adams PetscErrorCode ierr; 3846618991cSMark Adams MPI_Comm comm; 3856618991cSMark Adams Vec tmp_crds; 3866618991cSMark Adams Mat_MPIAIJ *mpimat = (Mat_MPIAIJ*)Gmat->data; 3876618991cSMark Adams PetscInt nnodes,num_ghosts,dir,kk,jj,my0,Iend,nloc; 3886618991cSMark Adams PetscScalar *data_arr; 3896618991cSMark Adams PetscReal *datas; 3906618991cSMark Adams PetscBool isMPIAIJ; 3916618991cSMark Adams 3926618991cSMark Adams PetscFunctionBegin; 3936618991cSMark Adams ierr = PetscObjectGetComm((PetscObject)Gmat,&comm);CHKERRQ(ierr); 3946618991cSMark Adams ierr = PetscObjectTypeCompare((PetscObject)Gmat, MATMPIAIJ, &isMPIAIJ);CHKERRQ(ierr); 3956618991cSMark Adams ierr = MatGetOwnershipRange(Gmat, &my0, &Iend);CHKERRQ(ierr); 3966618991cSMark Adams nloc = Iend - my0; 3976618991cSMark Adams ierr = VecGetLocalSize(mpimat->lvec, &num_ghosts);CHKERRQ(ierr); 3986618991cSMark Adams nnodes = num_ghosts + nloc; 3996618991cSMark Adams *a_stride = nnodes; 4006618991cSMark Adams ierr = MatCreateVecs(Gmat, &tmp_crds, 0);CHKERRQ(ierr); 4016618991cSMark Adams 4026618991cSMark Adams ierr = PetscMalloc1(data_sz*nnodes, &datas);CHKERRQ(ierr); 4036618991cSMark Adams for (dir=0; dir<data_sz; dir++) { 4046618991cSMark Adams /* set local, and global */ 4056618991cSMark Adams for (kk=0; kk<nloc; kk++) { 4066618991cSMark Adams PetscInt gid = my0 + kk; 4076618991cSMark Adams PetscScalar crd = (PetscScalar)data_in[dir*nloc + kk]; /* col oriented */ 4086618991cSMark Adams datas[dir*nnodes + kk] = PetscRealPart(crd); 4096618991cSMark Adams 4106618991cSMark Adams ierr = VecSetValues(tmp_crds, 1, &gid, &crd, INSERT_VALUES);CHKERRQ(ierr); 4116618991cSMark Adams } 4126618991cSMark Adams ierr = VecAssemblyBegin(tmp_crds);CHKERRQ(ierr); 4136618991cSMark Adams ierr = VecAssemblyEnd(tmp_crds);CHKERRQ(ierr); 4146618991cSMark Adams /* get ghost datas */ 4156618991cSMark Adams ierr = VecScatterBegin(mpimat->Mvctx,tmp_crds,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 4166618991cSMark Adams ierr = VecScatterEnd(mpimat->Mvctx,tmp_crds,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 4176618991cSMark Adams ierr = VecGetArray(mpimat->lvec, &data_arr);CHKERRQ(ierr); 4186618991cSMark Adams for (kk=nloc,jj=0;jj<num_ghosts;kk++,jj++) datas[dir*nnodes + kk] = PetscRealPart(data_arr[jj]); 4196618991cSMark Adams ierr = VecRestoreArray(mpimat->lvec, &data_arr);CHKERRQ(ierr); 4206618991cSMark Adams } 4216618991cSMark Adams ierr = VecDestroy(&tmp_crds);CHKERRQ(ierr); 4226618991cSMark Adams *a_data_out = datas; 4236618991cSMark Adams PetscFunctionReturn(0); 4246618991cSMark Adams } 4256618991cSMark Adams 4266618991cSMark Adams 4276618991cSMark Adams /* 4286618991cSMark Adams * 429*1943db53SBarry Smith * PCGAMGHashTableCreate 4306618991cSMark Adams */ 4316618991cSMark Adams 4326618991cSMark Adams #undef __FUNCT__ 433*1943db53SBarry Smith #define __FUNCT__ "PCGAMGHashTableCreate" 434*1943db53SBarry Smith PetscErrorCode PCGAMGHashTableCreate(PetscInt a_size, PCGAMGHashTable *a_tab) 4356618991cSMark Adams { 4366618991cSMark Adams PetscErrorCode ierr; 4376618991cSMark Adams PetscInt kk; 4386618991cSMark Adams 4396618991cSMark Adams PetscFunctionBegin; 4406618991cSMark Adams a_tab->size = a_size; 4416618991cSMark Adams ierr = PetscMalloc1(a_size, &a_tab->table);CHKERRQ(ierr); 4426618991cSMark Adams ierr = PetscMalloc1(a_size, &a_tab->data);CHKERRQ(ierr); 4436618991cSMark Adams for (kk=0; kk<a_size; kk++) a_tab->table[kk] = -1; 4446618991cSMark Adams PetscFunctionReturn(0); 4456618991cSMark Adams } 4466618991cSMark Adams 4476618991cSMark Adams #undef __FUNCT__ 448*1943db53SBarry Smith #define __FUNCT__ "PCGAMGHashTableDestroy" 449*1943db53SBarry Smith PetscErrorCode PCGAMGHashTableDestroy(PCGAMGHashTable *a_tab) 4506618991cSMark Adams { 4516618991cSMark Adams PetscErrorCode ierr; 4526618991cSMark Adams 4536618991cSMark Adams PetscFunctionBegin; 4546618991cSMark Adams ierr = PetscFree(a_tab->table);CHKERRQ(ierr); 4556618991cSMark Adams ierr = PetscFree(a_tab->data);CHKERRQ(ierr); 4566618991cSMark Adams PetscFunctionReturn(0); 4576618991cSMark Adams } 4586618991cSMark Adams 4596618991cSMark Adams #undef __FUNCT__ 460*1943db53SBarry Smith #define __FUNCT__ "PCGAMGHashTableAdd" 461*1943db53SBarry Smith PetscErrorCode PCGAMGHashTableAdd(PCGAMGHashTable *a_tab, PetscInt a_key, PetscInt a_data) 4626618991cSMark Adams { 4636618991cSMark Adams PetscInt kk,idx; 4646618991cSMark Adams 4656618991cSMark Adams PetscFunctionBegin; 4666618991cSMark Adams if (a_key<0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Negative key %d.",a_key); 4676618991cSMark Adams for (kk = 0, idx = GAMG_HASH(a_key); 4686618991cSMark Adams kk < a_tab->size; 4696618991cSMark Adams kk++, idx = (idx==(a_tab->size-1)) ? 0 : idx + 1) { 4706618991cSMark Adams 4716618991cSMark Adams if (a_tab->table[idx] == a_key) { 4726618991cSMark Adams /* exists */ 4736618991cSMark Adams a_tab->data[idx] = a_data; 4746618991cSMark Adams break; 4756618991cSMark Adams } else if (a_tab->table[idx] == -1) { 4766618991cSMark Adams /* add */ 4776618991cSMark Adams a_tab->table[idx] = a_key; 4786618991cSMark Adams a_tab->data[idx] = a_data; 4796618991cSMark Adams break; 4806618991cSMark Adams } 4816618991cSMark Adams } 4826618991cSMark Adams if (kk==a_tab->size) { 4836618991cSMark Adams /* this is not to efficient, waiting until completely full */ 4846618991cSMark Adams PetscInt oldsize = a_tab->size, new_size = 2*a_tab->size + 5, *oldtable = a_tab->table, *olddata = a_tab->data; 4856618991cSMark Adams PetscErrorCode ierr; 4866618991cSMark Adams 4876618991cSMark Adams a_tab->size = new_size; 4886618991cSMark Adams 4896618991cSMark Adams ierr = PetscMalloc1(a_tab->size, &a_tab->table);CHKERRQ(ierr); 4906618991cSMark Adams ierr = PetscMalloc1(a_tab->size, &a_tab->data);CHKERRQ(ierr); 4916618991cSMark Adams 4926618991cSMark Adams for (kk=0;kk<a_tab->size;kk++) a_tab->table[kk] = -1; 4936618991cSMark Adams for (kk=0;kk<oldsize;kk++) { 4946618991cSMark Adams if (oldtable[kk] != -1) { 495*1943db53SBarry Smith ierr = PCGAMGHashTableAdd(a_tab, oldtable[kk], olddata[kk]);CHKERRQ(ierr); 4966618991cSMark Adams } 4976618991cSMark Adams } 4986618991cSMark Adams ierr = PetscFree(oldtable);CHKERRQ(ierr); 4996618991cSMark Adams ierr = PetscFree(olddata);CHKERRQ(ierr); 500*1943db53SBarry Smith ierr = PCGAMGHashTableAdd(a_tab, a_key, a_data);CHKERRQ(ierr); 5016618991cSMark Adams } 5026618991cSMark Adams PetscFunctionReturn(0); 5036618991cSMark Adams } 5046618991cSMark Adams 505