18be712e4SBarry Smith /* 28be712e4SBarry Smith Provides the code that allows PETSc users to register their own 38be712e4SBarry Smith sequential matrix Ordering routines. 48be712e4SBarry Smith */ 58be712e4SBarry Smith #include <petsc/private/matimpl.h> 68be712e4SBarry Smith #include <petscmat.h> /*I "petscmat.h" I*/ 78be712e4SBarry Smith 88be712e4SBarry Smith PetscFunctionList MatOrderingList = NULL; 98be712e4SBarry Smith PetscBool MatOrderingRegisterAllCalled = PETSC_FALSE; 108be712e4SBarry Smith 118be712e4SBarry Smith PETSC_INTERN PetscErrorCode MatGetOrdering_Natural(Mat mat, MatOrderingType type, IS *irow, IS *icol) 128be712e4SBarry Smith { 138be712e4SBarry Smith PetscInt n, i, *ii; 148be712e4SBarry Smith PetscBool done; 158be712e4SBarry Smith MPI_Comm comm; 168be712e4SBarry Smith 178be712e4SBarry Smith PetscFunctionBegin; 188be712e4SBarry Smith PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 198be712e4SBarry Smith PetscCall(MatGetRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, &n, NULL, NULL, &done)); 208be712e4SBarry Smith PetscCall(MatRestoreRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, NULL, NULL, NULL, &done)); 218be712e4SBarry Smith if (done) { /* matrix may be "compressed" in symbolic factorization, due to i-nodes or block storage */ 228be712e4SBarry Smith /* 238be712e4SBarry Smith We actually create general index sets because this avoids mallocs to 248be712e4SBarry Smith to obtain the indices in the MatSolve() routines. 258be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF,n,0,1,irow)); 268be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF,n,0,1,icol)); 278be712e4SBarry Smith */ 288be712e4SBarry Smith PetscCall(PetscMalloc1(n, &ii)); 298be712e4SBarry Smith for (i = 0; i < n; i++) ii[i] = i; 308be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, ii, PETSC_COPY_VALUES, irow)); 318be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, ii, PETSC_OWN_POINTER, icol)); 328be712e4SBarry Smith } else { 338be712e4SBarry Smith PetscInt start, end; 348be712e4SBarry Smith 358be712e4SBarry Smith PetscCall(MatGetOwnershipRange(mat, &start, &end)); 368be712e4SBarry Smith PetscCall(ISCreateStride(comm, end - start, start, 1, irow)); 378be712e4SBarry Smith PetscCall(ISCreateStride(comm, end - start, start, 1, icol)); 388be712e4SBarry Smith } 398be712e4SBarry Smith PetscCall(ISSetIdentity(*irow)); 408be712e4SBarry Smith PetscCall(ISSetIdentity(*icol)); 418be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 428be712e4SBarry Smith } 438be712e4SBarry Smith 448be712e4SBarry Smith /* 458be712e4SBarry Smith Orders the rows (and columns) by the lengths of the rows. 468be712e4SBarry Smith This produces a symmetric Ordering but does not require a 478be712e4SBarry Smith matrix with symmetric non-zero structure. 488be712e4SBarry Smith */ 498be712e4SBarry Smith PETSC_INTERN PetscErrorCode MatGetOrdering_RowLength(Mat mat, MatOrderingType type, IS *irow, IS *icol) 508be712e4SBarry Smith { 518be712e4SBarry Smith PetscInt n, *permr, *lens, i; 528be712e4SBarry Smith const PetscInt *ia, *ja; 538be712e4SBarry Smith PetscBool done; 548be712e4SBarry Smith 558be712e4SBarry Smith PetscFunctionBegin; 568be712e4SBarry Smith PetscCall(MatGetRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, &n, &ia, &ja, &done)); 578be712e4SBarry Smith PetscCheck(done, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot get rows for matrix"); 588be712e4SBarry Smith 598be712e4SBarry Smith PetscCall(PetscMalloc2(n, &lens, n, &permr)); 608be712e4SBarry Smith for (i = 0; i < n; i++) { 618be712e4SBarry Smith lens[i] = ia[i + 1] - ia[i]; 628be712e4SBarry Smith permr[i] = i; 638be712e4SBarry Smith } 648be712e4SBarry Smith PetscCall(MatRestoreRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, NULL, &ia, &ja, &done)); 658be712e4SBarry Smith 668be712e4SBarry Smith PetscCall(PetscSortIntWithPermutation(n, lens, permr)); 678be712e4SBarry Smith 688be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, permr, PETSC_COPY_VALUES, irow)); 698be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, permr, PETSC_COPY_VALUES, icol)); 708be712e4SBarry Smith PetscCall(PetscFree2(lens, permr)); 718be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 728be712e4SBarry Smith } 738be712e4SBarry Smith 748be712e4SBarry Smith /*@C 758be712e4SBarry Smith MatOrderingRegister - Adds a new sparse matrix ordering to the matrix package. 768be712e4SBarry Smith 778be712e4SBarry Smith Not Collective 788be712e4SBarry Smith 798be712e4SBarry Smith Input Parameters: 808be712e4SBarry Smith + sname - name of ordering (for example `MATORDERINGND`) 818be712e4SBarry Smith - function - function pointer that creates the ordering 828be712e4SBarry Smith 838be712e4SBarry Smith Level: developer 848be712e4SBarry Smith 858be712e4SBarry Smith Example Usage: 868be712e4SBarry Smith .vb 878be712e4SBarry Smith MatOrderingRegister("my_order", MyOrder); 888be712e4SBarry Smith .ve 898be712e4SBarry Smith 90*a3b724e8SBarry Smith Then, your partitioner can be chosen with the procedural interface via `MatOrderingSetType(part, "my_order)` or at runtime via the option 91*a3b724e8SBarry Smith `-pc_factor_mat_ordering_type my_order` 928be712e4SBarry Smith 93*a3b724e8SBarry Smith .seealso: `Mat`, `MatOrderingType`, `MatOrderingRegisterAll()`, `MatGetOrdering()` 948be712e4SBarry Smith @*/ 958be712e4SBarry Smith PetscErrorCode MatOrderingRegister(const char sname[], PetscErrorCode (*function)(Mat, MatOrderingType, IS *, IS *)) 968be712e4SBarry Smith { 978be712e4SBarry Smith PetscFunctionBegin; 988be712e4SBarry Smith PetscCall(MatInitializePackage()); 998be712e4SBarry Smith PetscCall(PetscFunctionListAdd(&MatOrderingList, sname, function)); 1008be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 1018be712e4SBarry Smith } 1028be712e4SBarry Smith 1038be712e4SBarry Smith #include <../src/mat/impls/aij/mpi/mpiaij.h> 1048be712e4SBarry Smith /*@C 1058be712e4SBarry Smith MatGetOrdering - Gets a reordering for a matrix to reduce fill or to 1068be712e4SBarry Smith improve numerical stability of LU factorization. 1078be712e4SBarry Smith 1088be712e4SBarry Smith Collective 1098be712e4SBarry Smith 1108be712e4SBarry Smith Input Parameters: 1118be712e4SBarry Smith + mat - the matrix 1128be712e4SBarry Smith - type - type of reordering, one of the following 1138be712e4SBarry Smith .vb 1148be712e4SBarry Smith MATORDERINGNATURAL_OR_ND - Nested dissection unless matrix is SBAIJ then it is natural 1158be712e4SBarry Smith MATORDERINGNATURAL - Natural 1168be712e4SBarry Smith MATORDERINGND - Nested Dissection 1178be712e4SBarry Smith MATORDERING1WD - One-way Dissection 1188be712e4SBarry Smith MATORDERINGRCM - Reverse Cuthill-McKee 1198be712e4SBarry Smith MATORDERINGQMD - Quotient Minimum Degree 1208be712e4SBarry Smith MATORDERINGEXTERNAL - Use an ordering internal to the factorzation package and do not compute or use PETSc's 1218be712e4SBarry Smith .ve 1228be712e4SBarry Smith 1238be712e4SBarry Smith Output Parameters: 1248be712e4SBarry Smith + rperm - row permutation indices 1258be712e4SBarry Smith - cperm - column permutation indices 1268be712e4SBarry Smith 1278be712e4SBarry Smith Options Database Key: 1288be712e4SBarry Smith + -mat_view_ordering draw - plots matrix nonzero structure in new ordering 129bc50768fSJose E. Roman - -pc_factor_mat_ordering_type <nd,natural,..> - ordering to use with `PC`s based on factorization, `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC` 1308be712e4SBarry Smith 1318be712e4SBarry Smith Level: intermediate 1328be712e4SBarry Smith 1338be712e4SBarry Smith Notes: 1348be712e4SBarry Smith This DOES NOT actually reorder the matrix; it merely returns two index sets 1358be712e4SBarry Smith that define a reordering. This is usually not used directly, rather use the 1368be712e4SBarry Smith options `PCFactorSetMatOrderingType()` 1378be712e4SBarry Smith 1388be712e4SBarry Smith The user can define additional orderings; see `MatOrderingRegister()`. 1398be712e4SBarry Smith 1408be712e4SBarry Smith These are generally only implemented for sequential sparse matrices. 1418be712e4SBarry Smith 1428be712e4SBarry Smith Some external packages that PETSc can use for direct factorization such as SuperLU_DIST do not accept orderings provided by 1438be712e4SBarry Smith this call. 1448be712e4SBarry Smith 1458be712e4SBarry Smith If `MATORDERINGEXTERNAL` is used then PETSc does not compute an ordering and utilizes one built into the factorization package 1468be712e4SBarry Smith 1478be712e4SBarry Smith .seealso: `MatOrderingRegister()`, `PCFactorSetMatOrderingType()`, `MatColoring`, `MatColoringCreate()`, `MatOrderingType`, `Mat` 1488be712e4SBarry Smith @*/ 1498be712e4SBarry Smith PetscErrorCode MatGetOrdering(Mat mat, MatOrderingType type, IS *rperm, IS *cperm) 1508be712e4SBarry Smith { 1518be712e4SBarry Smith PetscInt mmat, nmat, mis; 1528be712e4SBarry Smith PetscErrorCode (*r)(Mat, MatOrderingType, IS *, IS *); 1538be712e4SBarry Smith PetscBool flg, ismpiaij; 1548be712e4SBarry Smith 1558be712e4SBarry Smith PetscFunctionBegin; 1568be712e4SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1578be712e4SBarry Smith PetscAssertPointer(rperm, 3); 1588be712e4SBarry Smith PetscAssertPointer(cperm, 4); 1598be712e4SBarry Smith PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1608be712e4SBarry Smith PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1618be712e4SBarry Smith PetscCheck(type, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Ordering type cannot be null"); 1628be712e4SBarry Smith 1638be712e4SBarry Smith PetscCall(PetscStrcmp(type, MATORDERINGEXTERNAL, &flg)); 1648be712e4SBarry Smith if (flg) { 1658be712e4SBarry Smith *rperm = NULL; 1668be712e4SBarry Smith *cperm = NULL; 1678be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 1688be712e4SBarry Smith } 1698be712e4SBarry Smith 1708be712e4SBarry Smith /* This code is terrible. MatGetOrdering() multiple dispatch should use matrix and this code should move to impls/aij/mpi. */ 1718be712e4SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPIAIJ, &ismpiaij)); 1728be712e4SBarry Smith if (ismpiaij) { /* Reorder using diagonal block */ 1738be712e4SBarry Smith Mat Ad, Ao; 1748be712e4SBarry Smith const PetscInt *colmap; 1758be712e4SBarry Smith IS lrowperm, lcolperm; 1768be712e4SBarry Smith PetscInt i, rstart, rend, *idx; 1778be712e4SBarry Smith const PetscInt *lidx; 1788be712e4SBarry Smith 1798be712e4SBarry Smith PetscCall(MatMPIAIJGetSeqAIJ(mat, &Ad, &Ao, &colmap)); 1808be712e4SBarry Smith PetscCall(MatGetOrdering(Ad, type, &lrowperm, &lcolperm)); 1818be712e4SBarry Smith PetscCall(MatGetOwnershipRange(mat, &rstart, &rend)); 1828be712e4SBarry Smith /* Remap row index set to global space */ 1838be712e4SBarry Smith PetscCall(ISGetIndices(lrowperm, &lidx)); 1848be712e4SBarry Smith PetscCall(PetscMalloc1(rend - rstart, &idx)); 1858be712e4SBarry Smith for (i = 0; i + rstart < rend; i++) idx[i] = rstart + lidx[i]; 1868be712e4SBarry Smith PetscCall(ISRestoreIndices(lrowperm, &lidx)); 1878be712e4SBarry Smith PetscCall(ISDestroy(&lrowperm)); 1888be712e4SBarry Smith PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), rend - rstart, idx, PETSC_OWN_POINTER, rperm)); 1898be712e4SBarry Smith PetscCall(ISSetPermutation(*rperm)); 1908be712e4SBarry Smith /* Remap column index set to global space */ 1918be712e4SBarry Smith PetscCall(ISGetIndices(lcolperm, &lidx)); 1928be712e4SBarry Smith PetscCall(PetscMalloc1(rend - rstart, &idx)); 1938be712e4SBarry Smith for (i = 0; i + rstart < rend; i++) idx[i] = rstart + lidx[i]; 1948be712e4SBarry Smith PetscCall(ISRestoreIndices(lcolperm, &lidx)); 1958be712e4SBarry Smith PetscCall(ISDestroy(&lcolperm)); 1968be712e4SBarry Smith PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), rend - rstart, idx, PETSC_OWN_POINTER, cperm)); 1978be712e4SBarry Smith PetscCall(ISSetPermutation(*cperm)); 1988be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 1998be712e4SBarry Smith } 2008be712e4SBarry Smith 2018be712e4SBarry Smith if (!mat->rmap->N) { /* matrix has zero rows */ 2028be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, cperm)); 2038be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, rperm)); 2048be712e4SBarry Smith PetscCall(ISSetIdentity(*cperm)); 2058be712e4SBarry Smith PetscCall(ISSetIdentity(*rperm)); 2068be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 2078be712e4SBarry Smith } 2088be712e4SBarry Smith 2098be712e4SBarry Smith PetscCall(MatGetLocalSize(mat, &mmat, &nmat)); 2108be712e4SBarry Smith PetscCheck(mmat == nmat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be square matrix, rows %" PetscInt_FMT " columns %" PetscInt_FMT, mmat, nmat); 2118be712e4SBarry Smith 2128be712e4SBarry Smith PetscCall(MatOrderingRegisterAll()); 2138be712e4SBarry Smith PetscCall(PetscFunctionListFind(MatOrderingList, type, &r)); 2148be712e4SBarry Smith PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown or unregistered type: %s", type); 2158be712e4SBarry Smith 2168be712e4SBarry Smith PetscCall(PetscLogEventBegin(MAT_GetOrdering, mat, 0, 0, 0)); 2178be712e4SBarry Smith PetscCall((*r)(mat, type, rperm, cperm)); 2188be712e4SBarry Smith PetscCall(ISSetPermutation(*rperm)); 2198be712e4SBarry Smith PetscCall(ISSetPermutation(*cperm)); 2208be712e4SBarry Smith /* Adjust for inode (reduced matrix ordering) only if row permutation is smaller the matrix size */ 2218be712e4SBarry Smith PetscCall(ISGetLocalSize(*rperm, &mis)); 2228be712e4SBarry Smith if (mmat > mis) PetscCall(MatInodeAdjustForInodes(mat, rperm, cperm)); 2238be712e4SBarry Smith PetscCall(PetscLogEventEnd(MAT_GetOrdering, mat, 0, 0, 0)); 2248be712e4SBarry Smith 2258be712e4SBarry Smith PetscCall(PetscOptionsHasName(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-mat_view_ordering", &flg)); 2268be712e4SBarry Smith if (flg) { 2278be712e4SBarry Smith Mat tmat; 2288be712e4SBarry Smith PetscCall(MatPermute(mat, *rperm, *cperm, &tmat)); 2298be712e4SBarry Smith PetscCall(MatViewFromOptions(tmat, (PetscObject)mat, "-mat_view_ordering")); 2308be712e4SBarry Smith PetscCall(MatDestroy(&tmat)); 2318be712e4SBarry Smith } 2328be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 2338be712e4SBarry Smith } 2348be712e4SBarry Smith 2358be712e4SBarry Smith PetscErrorCode MatGetOrderingList(PetscFunctionList *list) 2368be712e4SBarry Smith { 2378be712e4SBarry Smith PetscFunctionBegin; 2388be712e4SBarry Smith *list = MatOrderingList; 2398be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 2408be712e4SBarry Smith } 241