1c094ef40SMatthew G. Knepley #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 2e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h> 3c094ef40SMatthew G. Knepley 4c094ef40SMatthew G. Knepley typedef struct { 5e8f14785SLisandro Dalcin PetscHSetIJ ht; 6c094ef40SMatthew G. Knepley PetscInt *dnz, *onz; 7c09129f1SStefano Zampini PetscInt *dnzu, *onzu; 8f8f6e9aeSStefano Zampini PetscBool nooffproc; 9fcc385faSPatrick Sanan PetscBool used; 10c094ef40SMatthew G. Knepley } Mat_Preallocator; 11c094ef40SMatthew G. Knepley 1266976f2fSJacob Faibussowitsch static PetscErrorCode MatDestroy_Preallocator(Mat A) 13d71ae5a4SJacob Faibussowitsch { 14c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 15c094ef40SMatthew G. Knepley 16c094ef40SMatthew G. Knepley PetscFunctionBegin; 179566063dSJacob Faibussowitsch PetscCall(MatStashDestroy_Private(&A->stash)); 189566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&p->ht)); 199566063dSJacob Faibussowitsch PetscCall(PetscFree4(p->dnz, p->onz, p->dnzu, p->onzu)); 209566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 219566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatPreallocatorPreallocate_C", NULL)); 233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 24c094ef40SMatthew G. Knepley } 25c094ef40SMatthew G. Knepley 2666976f2fSJacob Faibussowitsch static PetscErrorCode MatSetUp_Preallocator(Mat A) 27d71ae5a4SJacob Faibussowitsch { 28c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 295dca1104SStefano Zampini PetscInt m, bs, mbs; 30c094ef40SMatthew G. Knepley 31c094ef40SMatthew G. Knepley PetscFunctionBegin; 329566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 339566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 349566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 359566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&p->ht)); 369566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(A, &bs)); 378011973bSJunchao Zhang /* Do not bother bstash since MatPreallocator does not implement MatSetValuesBlocked */ 389566063dSJacob Faibussowitsch PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)A), 1, &A->stash)); 395dca1104SStefano Zampini /* arrays are for blocked rows/cols */ 405dca1104SStefano Zampini mbs = m / bs; 419566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(mbs, &p->dnz, mbs, &p->onz, mbs, &p->dnzu, mbs, &p->onzu)); 423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43c094ef40SMatthew G. Knepley } 44c094ef40SMatthew G. Knepley 4566976f2fSJacob Faibussowitsch static PetscErrorCode MatSetValues_Preallocator(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 46d71ae5a4SJacob Faibussowitsch { 47c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 485dca1104SStefano Zampini PetscInt rStart, rEnd, r, cStart, cEnd, c, bs; 49c094ef40SMatthew G. Knepley 50c094ef40SMatthew G. Knepley PetscFunctionBegin; 519566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(A, &bs)); 529566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd)); 539566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cStart, &cEnd)); 54c094ef40SMatthew G. Knepley for (r = 0; r < m; ++r) { 55e8f14785SLisandro Dalcin PetscHashIJKey key; 56e8f14785SLisandro Dalcin PetscBool missing; 57c094ef40SMatthew G. Knepley 58e8f14785SLisandro Dalcin key.i = rows[r]; 59e8f14785SLisandro Dalcin if (key.i < 0) continue; 60e8f14785SLisandro Dalcin if ((key.i < rStart) || (key.i >= rEnd)) { 619566063dSJacob Faibussowitsch PetscCall(MatStashValuesRow_Private(&A->stash, key.i, n, cols, values, PETSC_FALSE)); 625dca1104SStefano Zampini } else { /* Hash table is for blocked rows/cols */ 635dca1104SStefano Zampini key.i = rows[r] / bs; 64c094ef40SMatthew G. Knepley for (c = 0; c < n; ++c) { 655dca1104SStefano Zampini key.j = cols[c] / bs; 66e8f14785SLisandro Dalcin if (key.j < 0) continue; 679566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(p->ht, key, &missing)); 68c094ef40SMatthew G. Knepley if (missing) { 695dca1104SStefano Zampini if ((key.j >= cStart / bs) && (key.j < cEnd / bs)) { 705dca1104SStefano Zampini ++p->dnz[key.i - rStart / bs]; 715dca1104SStefano Zampini if (key.j >= key.i) ++p->dnzu[key.i - rStart / bs]; 72c09129f1SStefano Zampini } else { 735dca1104SStefano Zampini ++p->onz[key.i - rStart / bs]; 745dca1104SStefano Zampini if (key.j >= key.i) ++p->onzu[key.i - rStart / bs]; 75c09129f1SStefano Zampini } 76c094ef40SMatthew G. Knepley } 77c094ef40SMatthew G. Knepley } 78c094ef40SMatthew G. Knepley } 79c094ef40SMatthew G. Knepley } 803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 81c094ef40SMatthew G. Knepley } 82c094ef40SMatthew G. Knepley 8366976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Preallocator(Mat A, MatAssemblyType type) 84d71ae5a4SJacob Faibussowitsch { 85c094ef40SMatthew G. Knepley PetscInt nstash, reallocs; 86c094ef40SMatthew G. Knepley 87c094ef40SMatthew G. Knepley PetscFunctionBegin; 889566063dSJacob Faibussowitsch PetscCall(MatStashScatterBegin_Private(A, &A->stash, A->rmap->range)); 899566063dSJacob Faibussowitsch PetscCall(MatStashGetInfo_Private(&A->stash, &nstash, &reallocs)); 909566063dSJacob Faibussowitsch PetscCall(PetscInfo(A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs)); 913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 92c094ef40SMatthew G. Knepley } 93c094ef40SMatthew G. Knepley 9466976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Preallocator(Mat A, MatAssemblyType type) 95d71ae5a4SJacob Faibussowitsch { 96c094ef40SMatthew G. Knepley PetscScalar *val; 97c094ef40SMatthew G. Knepley PetscInt *row, *col; 98c094ef40SMatthew G. Knepley PetscInt i, j, rstart, ncols, flg; 99c094ef40SMatthew G. Knepley PetscMPIInt n; 100f8f6e9aeSStefano Zampini Mat_Preallocator *p = (Mat_Preallocator *)A->data; 101c094ef40SMatthew G. Knepley 102c094ef40SMatthew G. Knepley PetscFunctionBegin; 103f8f6e9aeSStefano Zampini p->nooffproc = PETSC_TRUE; 104c094ef40SMatthew G. Knepley while (1) { 1059566063dSJacob Faibussowitsch PetscCall(MatStashScatterGetMesg_Private(&A->stash, &n, &row, &col, &val, &flg)); 106f8f6e9aeSStefano Zampini if (flg) p->nooffproc = PETSC_FALSE; 107c094ef40SMatthew G. Knepley if (!flg) break; 108c094ef40SMatthew G. Knepley 109c094ef40SMatthew G. Knepley for (i = 0; i < n;) { 110c094ef40SMatthew G. Knepley /* Now identify the consecutive vals belonging to the same row */ 111c094ef40SMatthew G. Knepley for (j = i, rstart = row[j]; j < n; j++) { 112c094ef40SMatthew G. Knepley if (row[j] != rstart) break; 113c094ef40SMatthew G. Knepley } 114c094ef40SMatthew G. Knepley if (j < n) ncols = j - i; 115c094ef40SMatthew G. Knepley else ncols = n - i; 116c094ef40SMatthew G. Knepley /* Now assemble all these values with a single function call */ 1179566063dSJacob Faibussowitsch PetscCall(MatSetValues_Preallocator(A, 1, row + i, ncols, col + i, val + i, INSERT_VALUES)); 118c094ef40SMatthew G. Knepley i = j; 119c094ef40SMatthew G. Knepley } 120c094ef40SMatthew G. Knepley } 1219566063dSJacob Faibussowitsch PetscCall(MatStashScatterEnd_Private(&A->stash)); 1221c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &p->nooffproc, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 1233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124c094ef40SMatthew G. Knepley } 125c094ef40SMatthew G. Knepley 12666976f2fSJacob Faibussowitsch static PetscErrorCode MatView_Preallocator(Mat A, PetscViewer viewer) 127d71ae5a4SJacob Faibussowitsch { 128c094ef40SMatthew G. Knepley PetscFunctionBegin; 1293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130c094ef40SMatthew G. Knepley } 131c094ef40SMatthew G. Knepley 13266976f2fSJacob Faibussowitsch static PetscErrorCode MatSetOption_Preallocator(Mat A, MatOption op, PetscBool flg) 133d71ae5a4SJacob Faibussowitsch { 134c094ef40SMatthew G. Knepley PetscFunctionBegin; 1353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 136c094ef40SMatthew G. Knepley } 137c094ef40SMatthew G. Knepley 13866976f2fSJacob Faibussowitsch static PetscErrorCode MatPreallocatorPreallocate_Preallocator(Mat mat, PetscBool fill, Mat A) 139d71ae5a4SJacob Faibussowitsch { 140c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)mat->data; 141c094ef40SMatthew G. Knepley PetscInt bs; 142c094ef40SMatthew G. Knepley 143c094ef40SMatthew G. Knepley PetscFunctionBegin; 1442c71b3e2SJacob Faibussowitsch PetscCheck(!p->used, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MatPreallocatorPreallocate() can only be used once for a give MatPreallocator object. Consider using MatDuplicate() after preallocation."); 145fcc385faSPatrick Sanan p->used = PETSC_TRUE; 1469566063dSJacob Faibussowitsch if (!fill) PetscCall(PetscHSetIJDestroy(&p->ht)); 1479566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(mat, &bs)); 1489566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(A, bs, p->dnz, p->onz, p->dnzu, p->onzu)); 1499566063dSJacob Faibussowitsch PetscCall(MatSetUp(A)); 1509566063dSJacob Faibussowitsch PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 151380bf85aSDave May if (fill) { 152a6f8f0ebSPatrick Sanan PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, p->nooffproc)); 153380bf85aSDave May PetscHashIter hi; 154380bf85aSDave May PetscHashIJKey key; 155380bf85aSDave May PetscScalar *zeros; 156880e7892SJed Brown PetscInt n, maxrow = 1, *cols, rStart, rEnd, *rowstarts; 157380bf85aSDave May 1589566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd)); 159880e7892SJed Brown // Ownership range is in terms of scalar entries, but we deal with blocks 160880e7892SJed Brown rStart /= bs; 161880e7892SJed Brown rEnd /= bs; 1629566063dSJacob Faibussowitsch PetscCall(PetscHSetIJGetSize(p->ht, &n)); 1639566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &cols, rEnd - rStart + 1, &rowstarts)); 164880e7892SJed Brown rowstarts[0] = 0; 165880e7892SJed Brown for (PetscInt i = 0; i < rEnd - rStart; i++) { 166880e7892SJed Brown rowstarts[i + 1] = rowstarts[i] + p->dnz[i] + p->onz[i]; 167880e7892SJed Brown maxrow = PetscMax(maxrow, p->dnz[i] + p->onz[i]); 168880e7892SJed Brown } 16908401ef6SPierre Jolivet PetscCheck(rowstarts[rEnd - rStart] == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hash claims %" PetscInt_FMT " entries, but dnz+onz counts %" PetscInt_FMT, n, rowstarts[rEnd - rStart]); 170880e7892SJed Brown 171380bf85aSDave May PetscHashIterBegin(p->ht, hi); 172c599c493SJunchao Zhang while (!PetscHashIterAtEnd(p->ht, hi)) { 173380bf85aSDave May PetscHashIterGetKey(p->ht, hi, key); 174880e7892SJed Brown PetscInt lrow = key.i - rStart; 175880e7892SJed Brown cols[rowstarts[lrow]] = key.j; 176880e7892SJed Brown rowstarts[lrow]++; 177380bf85aSDave May PetscHashIterNext(p->ht, hi); 178146543f8SJed Brown } 1799566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&p->ht)); 180146543f8SJed Brown 1819566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxrow * bs * bs, &zeros)); 182880e7892SJed Brown for (PetscInt i = 0; i < rEnd - rStart; i++) { 183880e7892SJed Brown PetscInt grow = rStart + i; 184880e7892SJed Brown PetscInt end = rowstarts[i], start = end - p->dnz[i] - p->onz[i]; 185*8e3a54c0SPierre Jolivet PetscCall(PetscSortInt(end - start, PetscSafePointerPlusOffset(cols, start))); 186*8e3a54c0SPierre Jolivet PetscCall(MatSetValuesBlocked(A, 1, &grow, end - start, PetscSafePointerPlusOffset(cols, start), zeros, INSERT_VALUES)); 187380bf85aSDave May } 1889566063dSJacob Faibussowitsch PetscCall(PetscFree(zeros)); 1899566063dSJacob Faibussowitsch PetscCall(PetscFree2(cols, rowstarts)); 190380bf85aSDave May 1919566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1929566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 193a6f8f0ebSPatrick Sanan PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_FALSE)); 194380bf85aSDave May } 1953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 196c094ef40SMatthew G. Knepley } 197c094ef40SMatthew G. Knepley 198c094ef40SMatthew G. Knepley /*@ 19911a5261eSBarry Smith MatPreallocatorPreallocate - Preallocates the A matrix, using information from a `MATPREALLOCATOR` mat, optionally filling A with zeros 200c094ef40SMatthew G. Knepley 201d8d19677SJose E. Roman Input Parameters: 20211a5261eSBarry Smith + mat - the `MATPREALLOCATOR` preallocator matrix 203380bf85aSDave May . fill - fill the matrix with zeros 204380bf85aSDave May - A - the matrix to be preallocated 205c094ef40SMatthew G. Knepley 206380bf85aSDave May Notes: 20711a5261eSBarry Smith This `MatType` implementation provides a helper utility to define the correct 208380bf85aSDave May preallocation data for a given nonzero structure. Use this object like a 209380bf85aSDave May regular matrix, e.g. loop over the nonzero structure of the matrix and 21011a5261eSBarry Smith call `MatSetValues()` or `MatSetValuesBlocked()` to indicate the nonzero locations. 21111a5261eSBarry Smith The matrix entries provided to `MatSetValues()` will be ignored, it only uses 212380bf85aSDave May the row / col indices provided to determine the information required to be 21311a5261eSBarry Smith passed to `MatXAIJSetPreallocation()`. Once you have looped over the nonzero 21411a5261eSBarry Smith structure, you must call `MatAssemblyBegin()`, `MatAssemblyEnd()` on mat. 215380bf85aSDave May 21611a5261eSBarry Smith After you have assembled the preallocator matrix (mat), call `MatPreallocatorPreallocate()` 217380bf85aSDave May to define the preallocation information on the matrix (A). Setting the parameter 21811a5261eSBarry Smith fill = PETSC_TRUE will insert zeros into the matrix A. Internally `MatPreallocatorPreallocate()` 21911a5261eSBarry Smith will call `MatSetOption`(A, `MAT_NEW_NONZERO_ALLOCATION_ERR`, `PETSC_TRUE`); 220c094ef40SMatthew G. Knepley 22111a5261eSBarry Smith This function may only be called once for a given `MATPREALLOCATOR` object. If 22211a5261eSBarry Smith multiple `Mat`s need to be preallocated, consider using `MatDuplicate()` after 223fcc385faSPatrick Sanan this function. 224fcc385faSPatrick Sanan 225c094ef40SMatthew G. Knepley Level: advanced 226c094ef40SMatthew G. Knepley 22711a5261eSBarry Smith .seealso: `MATPREALLOCATOR`, `MatXAIJSetPreallocation()` 228c094ef40SMatthew G. Knepley @*/ 229d71ae5a4SJacob Faibussowitsch PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A) 230d71ae5a4SJacob Faibussowitsch { 231c094ef40SMatthew G. Knepley PetscFunctionBegin; 232c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 233d60670a5SStefano Zampini PetscValidLogicalCollectiveBool(mat, fill, 2); 234c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(A, MAT_CLASSID, 3); 235cac4c232SBarry Smith PetscUseMethod(mat, "MatPreallocatorPreallocate_C", (Mat, PetscBool, Mat), (mat, fill, A)); 2363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 237c094ef40SMatthew G. Knepley } 238c094ef40SMatthew G. Knepley 239c094ef40SMatthew G. Knepley /*MC 240c094ef40SMatthew G. Knepley MATPREALLOCATOR - MATPREALLOCATOR = "preallocator" - A matrix type to be used for computing a matrix preallocation. 241c094ef40SMatthew G. Knepley 242c094ef40SMatthew G. Knepley Operations Provided: 24367b8a455SSatish Balay .vb 24467b8a455SSatish Balay MatSetValues() 24567b8a455SSatish Balay .ve 246c094ef40SMatthew G. Knepley 247c094ef40SMatthew G. Knepley Options Database Keys: 24811a5261eSBarry Smith . -mat_type preallocator - sets the matrix type to `MATPREALLOCATOR` during a call to `MatSetFromOptions()` 249c094ef40SMatthew G. Knepley 250c094ef40SMatthew G. Knepley Level: advanced 251c094ef40SMatthew G. Knepley 25211a5261eSBarry Smith .seealso: `MATPREALLOCATOR`, `Mat`, `MatPreallocatorPreallocate()` 253c094ef40SMatthew G. Knepley M*/ 254c094ef40SMatthew G. Knepley 255d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A) 256d71ae5a4SJacob Faibussowitsch { 257c094ef40SMatthew G. Knepley Mat_Preallocator *p; 258c094ef40SMatthew G. Knepley 259c094ef40SMatthew G. Knepley PetscFunctionBegin; 2604dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&p)); 261c094ef40SMatthew G. Knepley A->data = (void *)p; 262c094ef40SMatthew G. Knepley 263c094ef40SMatthew G. Knepley p->ht = NULL; 264c094ef40SMatthew G. Knepley p->dnz = NULL; 265c094ef40SMatthew G. Knepley p->onz = NULL; 266c09129f1SStefano Zampini p->dnzu = NULL; 267c09129f1SStefano Zampini p->onzu = NULL; 268fcc385faSPatrick Sanan p->used = PETSC_FALSE; 269c094ef40SMatthew G. Knepley 270c094ef40SMatthew G. Knepley /* matrix ops */ 2719566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps))); 272c09129f1SStefano Zampini 273c094ef40SMatthew G. Knepley A->ops->destroy = MatDestroy_Preallocator; 274c094ef40SMatthew G. Knepley A->ops->setup = MatSetUp_Preallocator; 275c094ef40SMatthew G. Knepley A->ops->setvalues = MatSetValues_Preallocator; 276c094ef40SMatthew G. Knepley A->ops->assemblybegin = MatAssemblyBegin_Preallocator; 277c094ef40SMatthew G. Knepley A->ops->assemblyend = MatAssemblyEnd_Preallocator; 278c094ef40SMatthew G. Knepley A->ops->view = MatView_Preallocator; 279c094ef40SMatthew G. Knepley A->ops->setoption = MatSetOption_Preallocator; 2805dca1104SStefano Zampini A->ops->setblocksizes = MatSetBlockSizes_Default; /* once set, user is not allowed to change the block sizes */ 281c094ef40SMatthew G. Knepley 282c094ef40SMatthew G. Knepley /* special MATPREALLOCATOR functions */ 2839566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator)); 2849566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATPREALLOCATOR)); 2853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 286c094ef40SMatthew G. Knepley } 287