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 12*9371c9d4SSatish Balay PetscErrorCode MatDestroy_Preallocator(Mat A) { 13c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 14c094ef40SMatthew G. Knepley 15c094ef40SMatthew G. Knepley PetscFunctionBegin; 169566063dSJacob Faibussowitsch PetscCall(MatStashDestroy_Private(&A->stash)); 179566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&p->ht)); 189566063dSJacob Faibussowitsch PetscCall(PetscFree4(p->dnz, p->onz, p->dnzu, p->onzu)); 199566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 209566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatPreallocatorPreallocate_C", NULL)); 22c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 23c094ef40SMatthew G. Knepley } 24c094ef40SMatthew G. Knepley 25*9371c9d4SSatish Balay PetscErrorCode MatSetUp_Preallocator(Mat A) { 26c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 275dca1104SStefano Zampini PetscInt m, bs, mbs; 28c094ef40SMatthew G. Knepley 29c094ef40SMatthew G. Knepley PetscFunctionBegin; 309566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 319566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 329566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 339566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&p->ht)); 349566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(A, &bs)); 358011973bSJunchao Zhang /* Do not bother bstash since MatPreallocator does not implement MatSetValuesBlocked */ 369566063dSJacob Faibussowitsch PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)A), 1, &A->stash)); 375dca1104SStefano Zampini /* arrays are for blocked rows/cols */ 385dca1104SStefano Zampini mbs = m / bs; 399566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(mbs, &p->dnz, mbs, &p->onz, mbs, &p->dnzu, mbs, &p->onzu)); 40c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 41c094ef40SMatthew G. Knepley } 42c094ef40SMatthew G. Knepley 43*9371c9d4SSatish Balay PetscErrorCode MatSetValues_Preallocator(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) { 44c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)A->data; 455dca1104SStefano Zampini PetscInt rStart, rEnd, r, cStart, cEnd, c, bs; 46c094ef40SMatthew G. Knepley 47c094ef40SMatthew G. Knepley PetscFunctionBegin; 489566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(A, &bs)); 499566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd)); 509566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cStart, &cEnd)); 51c094ef40SMatthew G. Knepley for (r = 0; r < m; ++r) { 52e8f14785SLisandro Dalcin PetscHashIJKey key; 53e8f14785SLisandro Dalcin PetscBool missing; 54c094ef40SMatthew G. Knepley 55e8f14785SLisandro Dalcin key.i = rows[r]; 56e8f14785SLisandro Dalcin if (key.i < 0) continue; 57e8f14785SLisandro Dalcin if ((key.i < rStart) || (key.i >= rEnd)) { 589566063dSJacob Faibussowitsch PetscCall(MatStashValuesRow_Private(&A->stash, key.i, n, cols, values, PETSC_FALSE)); 595dca1104SStefano Zampini } else { /* Hash table is for blocked rows/cols */ 605dca1104SStefano Zampini key.i = rows[r] / bs; 61c094ef40SMatthew G. Knepley for (c = 0; c < n; ++c) { 625dca1104SStefano Zampini key.j = cols[c] / bs; 63e8f14785SLisandro Dalcin if (key.j < 0) continue; 649566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(p->ht, key, &missing)); 65c094ef40SMatthew G. Knepley if (missing) { 665dca1104SStefano Zampini if ((key.j >= cStart / bs) && (key.j < cEnd / bs)) { 675dca1104SStefano Zampini ++p->dnz[key.i - rStart / bs]; 685dca1104SStefano Zampini if (key.j >= key.i) ++p->dnzu[key.i - rStart / bs]; 69c09129f1SStefano Zampini } else { 705dca1104SStefano Zampini ++p->onz[key.i - rStart / bs]; 715dca1104SStefano Zampini if (key.j >= key.i) ++p->onzu[key.i - rStart / bs]; 72c09129f1SStefano Zampini } 73c094ef40SMatthew G. Knepley } 74c094ef40SMatthew G. Knepley } 75c094ef40SMatthew G. Knepley } 76c094ef40SMatthew G. Knepley } 77c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 78c094ef40SMatthew G. Knepley } 79c094ef40SMatthew G. Knepley 80*9371c9d4SSatish Balay PetscErrorCode MatAssemblyBegin_Preallocator(Mat A, MatAssemblyType type) { 81c094ef40SMatthew G. Knepley PetscInt nstash, reallocs; 82c094ef40SMatthew G. Knepley 83c094ef40SMatthew G. Knepley PetscFunctionBegin; 849566063dSJacob Faibussowitsch PetscCall(MatStashScatterBegin_Private(A, &A->stash, A->rmap->range)); 859566063dSJacob Faibussowitsch PetscCall(MatStashGetInfo_Private(&A->stash, &nstash, &reallocs)); 869566063dSJacob Faibussowitsch PetscCall(PetscInfo(A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs)); 87c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 88c094ef40SMatthew G. Knepley } 89c094ef40SMatthew G. Knepley 90*9371c9d4SSatish Balay PetscErrorCode MatAssemblyEnd_Preallocator(Mat A, MatAssemblyType type) { 91c094ef40SMatthew G. Knepley PetscScalar *val; 92c094ef40SMatthew G. Knepley PetscInt *row, *col; 93c094ef40SMatthew G. Knepley PetscInt i, j, rstart, ncols, flg; 94c094ef40SMatthew G. Knepley PetscMPIInt n; 95f8f6e9aeSStefano Zampini Mat_Preallocator *p = (Mat_Preallocator *)A->data; 96c094ef40SMatthew G. Knepley 97c094ef40SMatthew G. Knepley PetscFunctionBegin; 98f8f6e9aeSStefano Zampini p->nooffproc = PETSC_TRUE; 99c094ef40SMatthew G. Knepley while (1) { 1009566063dSJacob Faibussowitsch PetscCall(MatStashScatterGetMesg_Private(&A->stash, &n, &row, &col, &val, &flg)); 101f8f6e9aeSStefano Zampini if (flg) p->nooffproc = PETSC_FALSE; 102c094ef40SMatthew G. Knepley if (!flg) break; 103c094ef40SMatthew G. Knepley 104c094ef40SMatthew G. Knepley for (i = 0; i < n;) { 105c094ef40SMatthew G. Knepley /* Now identify the consecutive vals belonging to the same row */ 106c094ef40SMatthew G. Knepley for (j = i, rstart = row[j]; j < n; j++) { 107c094ef40SMatthew G. Knepley if (row[j] != rstart) break; 108c094ef40SMatthew G. Knepley } 109c094ef40SMatthew G. Knepley if (j < n) ncols = j - i; 110c094ef40SMatthew G. Knepley else ncols = n - i; 111c094ef40SMatthew G. Knepley /* Now assemble all these values with a single function call */ 1129566063dSJacob Faibussowitsch PetscCall(MatSetValues_Preallocator(A, 1, row + i, ncols, col + i, val + i, INSERT_VALUES)); 113c094ef40SMatthew G. Knepley i = j; 114c094ef40SMatthew G. Knepley } 115c094ef40SMatthew G. Knepley } 1169566063dSJacob Faibussowitsch PetscCall(MatStashScatterEnd_Private(&A->stash)); 1171c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &p->nooffproc, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 118c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 119c094ef40SMatthew G. Knepley } 120c094ef40SMatthew G. Knepley 121*9371c9d4SSatish Balay PetscErrorCode MatView_Preallocator(Mat A, PetscViewer viewer) { 122c094ef40SMatthew G. Knepley PetscFunctionBegin; 123c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 124c094ef40SMatthew G. Knepley } 125c094ef40SMatthew G. Knepley 126*9371c9d4SSatish Balay PetscErrorCode MatSetOption_Preallocator(Mat A, MatOption op, PetscBool flg) { 127c094ef40SMatthew G. Knepley PetscFunctionBegin; 128c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 129c094ef40SMatthew G. Knepley } 130c094ef40SMatthew G. Knepley 131*9371c9d4SSatish Balay PetscErrorCode MatPreallocatorPreallocate_Preallocator(Mat mat, PetscBool fill, Mat A) { 132c094ef40SMatthew G. Knepley Mat_Preallocator *p = (Mat_Preallocator *)mat->data; 133c094ef40SMatthew G. Knepley PetscInt bs; 134c094ef40SMatthew G. Knepley 135c094ef40SMatthew G. Knepley PetscFunctionBegin; 1362c71b3e2SJacob 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."); 137fcc385faSPatrick Sanan p->used = PETSC_TRUE; 1389566063dSJacob Faibussowitsch if (!fill) PetscCall(PetscHSetIJDestroy(&p->ht)); 1399566063dSJacob Faibussowitsch PetscCall(MatGetBlockSize(mat, &bs)); 1409566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(A, bs, p->dnz, p->onz, p->dnzu, p->onzu)); 1419566063dSJacob Faibussowitsch PetscCall(MatSetUp(A)); 1429566063dSJacob Faibussowitsch PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 143380bf85aSDave May if (fill) { 144a6f8f0ebSPatrick Sanan PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, p->nooffproc)); 145380bf85aSDave May PetscHashIter hi; 146380bf85aSDave May PetscHashIJKey key; 147380bf85aSDave May PetscScalar *zeros; 148880e7892SJed Brown PetscInt n, maxrow = 1, *cols, rStart, rEnd, *rowstarts; 149380bf85aSDave May 1509566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd)); 151880e7892SJed Brown // Ownership range is in terms of scalar entries, but we deal with blocks 152880e7892SJed Brown rStart /= bs; 153880e7892SJed Brown rEnd /= bs; 1549566063dSJacob Faibussowitsch PetscCall(PetscHSetIJGetSize(p->ht, &n)); 1559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &cols, rEnd - rStart + 1, &rowstarts)); 156880e7892SJed Brown rowstarts[0] = 0; 157880e7892SJed Brown for (PetscInt i = 0; i < rEnd - rStart; i++) { 158880e7892SJed Brown rowstarts[i + 1] = rowstarts[i] + p->dnz[i] + p->onz[i]; 159880e7892SJed Brown maxrow = PetscMax(maxrow, p->dnz[i] + p->onz[i]); 160880e7892SJed Brown } 16108401ef6SPierre 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]); 162880e7892SJed Brown 163380bf85aSDave May PetscHashIterBegin(p->ht, hi); 164c599c493SJunchao Zhang while (!PetscHashIterAtEnd(p->ht, hi)) { 165380bf85aSDave May PetscHashIterGetKey(p->ht, hi, key); 166880e7892SJed Brown PetscInt lrow = key.i - rStart; 167880e7892SJed Brown cols[rowstarts[lrow]] = key.j; 168880e7892SJed Brown rowstarts[lrow]++; 169380bf85aSDave May PetscHashIterNext(p->ht, hi); 170146543f8SJed Brown } 1719566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&p->ht)); 172146543f8SJed Brown 1739566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxrow * bs * bs, &zeros)); 174880e7892SJed Brown for (PetscInt i = 0; i < rEnd - rStart; i++) { 175880e7892SJed Brown PetscInt grow = rStart + i; 176880e7892SJed Brown PetscInt end = rowstarts[i], start = end - p->dnz[i] - p->onz[i]; 1779566063dSJacob Faibussowitsch PetscCall(PetscSortInt(end - start, &cols[start])); 1789566063dSJacob Faibussowitsch PetscCall(MatSetValuesBlocked(A, 1, &grow, end - start, &cols[start], zeros, INSERT_VALUES)); 179380bf85aSDave May } 1809566063dSJacob Faibussowitsch PetscCall(PetscFree(zeros)); 1819566063dSJacob Faibussowitsch PetscCall(PetscFree2(cols, rowstarts)); 182380bf85aSDave May 1839566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1849566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 185a6f8f0ebSPatrick Sanan PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_FALSE)); 186380bf85aSDave May } 187c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 188c094ef40SMatthew G. Knepley } 189c094ef40SMatthew G. Knepley 190c094ef40SMatthew G. Knepley /*@ 191380bf85aSDave May MatPreallocatorPreallocate - Preallocates the A matrix, using information from mat, optionally filling A with zeros 192c094ef40SMatthew G. Knepley 193d8d19677SJose E. Roman Input Parameters: 194c094ef40SMatthew G. Knepley + mat - the preallocator 195380bf85aSDave May . fill - fill the matrix with zeros 196380bf85aSDave May - A - the matrix to be preallocated 197c094ef40SMatthew G. Knepley 198380bf85aSDave May Notes: 199380bf85aSDave May This Mat implementation provides a helper utility to define the correct 200380bf85aSDave May preallocation data for a given nonzero structure. Use this object like a 201380bf85aSDave May regular matrix, e.g. loop over the nonzero structure of the matrix and 202380bf85aSDave May call MatSetValues() or MatSetValuesBlocked() to indicate the nonzero locations. 203a5b23f4aSJose E. Roman The matrix entries provided to MatSetValues() will be ignored, it only uses 204380bf85aSDave May the row / col indices provided to determine the information required to be 205380bf85aSDave May passed to MatXAIJSetPreallocation(). Once you have looped over the nonzero 206380bf85aSDave May structure, you must call MatAssemblyBegin(), MatAssemblyEnd() on mat. 207380bf85aSDave May 208380bf85aSDave May After you have assembled the preallocator matrix (mat), call MatPreallocatorPreallocate() 209380bf85aSDave May to define the preallocation information on the matrix (A). Setting the parameter 210380bf85aSDave May fill = PETSC_TRUE will insert zeros into the matrix A. Internally MatPreallocatorPreallocate() 211380bf85aSDave May will call MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE); 212c094ef40SMatthew G. Knepley 213fcc385faSPatrick Sanan This function may only be called once for a given MatPreallocator object. If 214fcc385faSPatrick Sanan multiple Mats need to be preallocated, consider using MatDuplicate() after 215fcc385faSPatrick Sanan this function. 216fcc385faSPatrick Sanan 217c094ef40SMatthew G. Knepley Level: advanced 218c094ef40SMatthew G. Knepley 219db781477SPatrick Sanan .seealso: `MATPREALLOCATOR` 220c094ef40SMatthew G. Knepley @*/ 221*9371c9d4SSatish Balay PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A) { 222c094ef40SMatthew G. Knepley PetscFunctionBegin; 223c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 224d60670a5SStefano Zampini PetscValidLogicalCollectiveBool(mat, fill, 2); 225c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(A, MAT_CLASSID, 3); 226cac4c232SBarry Smith PetscUseMethod(mat, "MatPreallocatorPreallocate_C", (Mat, PetscBool, Mat), (mat, fill, A)); 227c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 228c094ef40SMatthew G. Knepley } 229c094ef40SMatthew G. Knepley 230c094ef40SMatthew G. Knepley /*MC 231c094ef40SMatthew G. Knepley MATPREALLOCATOR - MATPREALLOCATOR = "preallocator" - A matrix type to be used for computing a matrix preallocation. 232c094ef40SMatthew G. Knepley 233c094ef40SMatthew G. Knepley Operations Provided: 23467b8a455SSatish Balay .vb 23567b8a455SSatish Balay MatSetValues() 23667b8a455SSatish Balay .ve 237c094ef40SMatthew G. Knepley 238c094ef40SMatthew G. Knepley Options Database Keys: 239c094ef40SMatthew G. Knepley . -mat_type preallocator - sets the matrix type to "preallocator" during a call to MatSetFromOptions() 240c094ef40SMatthew G. Knepley 241c094ef40SMatthew G. Knepley Level: advanced 242c094ef40SMatthew G. Knepley 243db781477SPatrick Sanan .seealso: `Mat`, `MatPreallocatorPreallocate()` 244c094ef40SMatthew G. Knepley 245c094ef40SMatthew G. Knepley M*/ 246c094ef40SMatthew G. Knepley 247*9371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A) { 248c094ef40SMatthew G. Knepley Mat_Preallocator *p; 249c094ef40SMatthew G. Knepley 250c094ef40SMatthew G. Knepley PetscFunctionBegin; 2519566063dSJacob Faibussowitsch PetscCall(PetscNewLog(A, &p)); 252c094ef40SMatthew G. Knepley A->data = (void *)p; 253c094ef40SMatthew G. Knepley 254c094ef40SMatthew G. Knepley p->ht = NULL; 255c094ef40SMatthew G. Knepley p->dnz = NULL; 256c094ef40SMatthew G. Knepley p->onz = NULL; 257c09129f1SStefano Zampini p->dnzu = NULL; 258c09129f1SStefano Zampini p->onzu = NULL; 259fcc385faSPatrick Sanan p->used = PETSC_FALSE; 260c094ef40SMatthew G. Knepley 261c094ef40SMatthew G. Knepley /* matrix ops */ 2629566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps))); 263c09129f1SStefano Zampini 264c094ef40SMatthew G. Knepley A->ops->destroy = MatDestroy_Preallocator; 265c094ef40SMatthew G. Knepley A->ops->setup = MatSetUp_Preallocator; 266c094ef40SMatthew G. Knepley A->ops->setvalues = MatSetValues_Preallocator; 267c094ef40SMatthew G. Knepley A->ops->assemblybegin = MatAssemblyBegin_Preallocator; 268c094ef40SMatthew G. Knepley A->ops->assemblyend = MatAssemblyEnd_Preallocator; 269c094ef40SMatthew G. Knepley A->ops->view = MatView_Preallocator; 270c094ef40SMatthew G. Knepley A->ops->setoption = MatSetOption_Preallocator; 2715dca1104SStefano Zampini A->ops->setblocksizes = MatSetBlockSizes_Default; /* once set, user is not allowed to change the block sizes */ 272c094ef40SMatthew G. Knepley 273c094ef40SMatthew G. Knepley /* special MATPREALLOCATOR functions */ 2749566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator)); 2759566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATPREALLOCATOR)); 276c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 277c094ef40SMatthew G. Knepley } 278