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 12c094ef40SMatthew G. Knepley PetscErrorCode MatDestroy_Preallocator(Mat A) 13c094ef40SMatthew G. Knepley { 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)); 23c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 24c094ef40SMatthew G. Knepley } 25c094ef40SMatthew G. Knepley 26c094ef40SMatthew G. Knepley PetscErrorCode MatSetUp_Preallocator(Mat A) 27c094ef40SMatthew G. Knepley { 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)); 42c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 43c094ef40SMatthew G. Knepley } 44c094ef40SMatthew G. Knepley 45c094ef40SMatthew G. Knepley PetscErrorCode MatSetValues_Preallocator(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 46c094ef40SMatthew G. Knepley { 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 } 80c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 81c094ef40SMatthew G. Knepley } 82c094ef40SMatthew G. Knepley 83c094ef40SMatthew G. Knepley PetscErrorCode MatAssemblyBegin_Preallocator(Mat A, MatAssemblyType type) 84c094ef40SMatthew G. Knepley { 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)); 91c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 92c094ef40SMatthew G. Knepley } 93c094ef40SMatthew G. Knepley 94c094ef40SMatthew G. Knepley PetscErrorCode MatAssemblyEnd_Preallocator(Mat A, MatAssemblyType type) 95c094ef40SMatthew G. Knepley { 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)); 1229566063dSJacob Faibussowitsch PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE,&p->nooffproc,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A))); 123c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 124c094ef40SMatthew G. Knepley } 125c094ef40SMatthew G. Knepley 126c094ef40SMatthew G. Knepley PetscErrorCode MatView_Preallocator(Mat A, PetscViewer viewer) 127c094ef40SMatthew G. Knepley { 128c094ef40SMatthew G. Knepley PetscFunctionBegin; 129c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 130c094ef40SMatthew G. Knepley } 131c094ef40SMatthew G. Knepley 132c094ef40SMatthew G. Knepley PetscErrorCode MatSetOption_Preallocator(Mat A, MatOption op, PetscBool flg) 133c094ef40SMatthew G. Knepley { 134c094ef40SMatthew G. Knepley PetscFunctionBegin; 135c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 136c094ef40SMatthew G. Knepley } 137c094ef40SMatthew G. Knepley 138c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate_Preallocator(Mat mat, PetscBool fill, Mat A) 139c094ef40SMatthew G. Knepley { 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)); 1519566063dSJacob Faibussowitsch PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, p->nooffproc)); 152380bf85aSDave May if (fill) { 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 } 1692c71b3e2SJacob Faibussowitsch PetscCheckFalse(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); 172146543f8SJed Brown for (PetscInt i=0; !PetscHashIterAtEnd(p->ht,hi); i++) { 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]; 1859566063dSJacob Faibussowitsch PetscCall(PetscSortInt(end-start,&cols[start])); 1869566063dSJacob Faibussowitsch PetscCall(MatSetValuesBlocked(A, 1, &grow, end-start, &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)); 193380bf85aSDave May } 194c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 195c094ef40SMatthew G. Knepley } 196c094ef40SMatthew G. Knepley 197c094ef40SMatthew G. Knepley /*@ 198380bf85aSDave May MatPreallocatorPreallocate - Preallocates the A matrix, using information from mat, optionally filling A with zeros 199c094ef40SMatthew G. Knepley 200d8d19677SJose E. Roman Input Parameters: 201c094ef40SMatthew G. Knepley + mat - the preallocator 202380bf85aSDave May . fill - fill the matrix with zeros 203380bf85aSDave May - A - the matrix to be preallocated 204c094ef40SMatthew G. Knepley 205380bf85aSDave May Notes: 206380bf85aSDave May This Mat implementation provides a helper utility to define the correct 207380bf85aSDave May preallocation data for a given nonzero structure. Use this object like a 208380bf85aSDave May regular matrix, e.g. loop over the nonzero structure of the matrix and 209380bf85aSDave May call MatSetValues() or MatSetValuesBlocked() to indicate the nonzero locations. 210a5b23f4aSJose E. Roman The matrix entries provided to MatSetValues() will be ignored, it only uses 211380bf85aSDave May the row / col indices provided to determine the information required to be 212380bf85aSDave May passed to MatXAIJSetPreallocation(). Once you have looped over the nonzero 213380bf85aSDave May structure, you must call MatAssemblyBegin(), MatAssemblyEnd() on mat. 214380bf85aSDave May 215380bf85aSDave May After you have assembled the preallocator matrix (mat), call MatPreallocatorPreallocate() 216380bf85aSDave May to define the preallocation information on the matrix (A). Setting the parameter 217380bf85aSDave May fill = PETSC_TRUE will insert zeros into the matrix A. Internally MatPreallocatorPreallocate() 218380bf85aSDave May will call MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE); 219c094ef40SMatthew G. Knepley 220fcc385faSPatrick Sanan This function may only be called once for a given MatPreallocator object. If 221fcc385faSPatrick Sanan multiple Mats need to be preallocated, consider using MatDuplicate() after 222fcc385faSPatrick Sanan this function. 223fcc385faSPatrick Sanan 224c094ef40SMatthew G. Knepley Level: advanced 225c094ef40SMatthew G. Knepley 226c094ef40SMatthew G. Knepley .seealso: MATPREALLOCATOR 227c094ef40SMatthew G. Knepley @*/ 228c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A) 229c094ef40SMatthew G. Knepley { 230c094ef40SMatthew G. Knepley PetscFunctionBegin; 231c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 232d60670a5SStefano Zampini PetscValidLogicalCollectiveBool(mat,fill,2); 233c094ef40SMatthew G. Knepley PetscValidHeaderSpecific(A,MAT_CLASSID,3); 234*cac4c232SBarry Smith PetscUseMethod(mat,"MatPreallocatorPreallocate_C",(Mat,PetscBool,Mat),(mat,fill,A)); 235c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 236c094ef40SMatthew G. Knepley } 237c094ef40SMatthew G. Knepley 238c094ef40SMatthew G. Knepley /*MC 239c094ef40SMatthew G. Knepley MATPREALLOCATOR - MATPREALLOCATOR = "preallocator" - A matrix type to be used for computing a matrix preallocation. 240c094ef40SMatthew G. Knepley 241c094ef40SMatthew G. Knepley Operations Provided: 24267b8a455SSatish Balay .vb 24367b8a455SSatish Balay MatSetValues() 24467b8a455SSatish Balay .ve 245c094ef40SMatthew G. Knepley 246c094ef40SMatthew G. Knepley Options Database Keys: 247c094ef40SMatthew G. Knepley . -mat_type preallocator - sets the matrix type to "preallocator" during a call to MatSetFromOptions() 248c094ef40SMatthew G. Knepley 249c094ef40SMatthew G. Knepley Level: advanced 250c094ef40SMatthew G. Knepley 251c74f52fcSPatrick Sanan .seealso: Mat, MatPreallocatorPreallocate() 252c094ef40SMatthew G. Knepley 253c094ef40SMatthew G. Knepley M*/ 254c094ef40SMatthew G. Knepley 255c094ef40SMatthew G. Knepley PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A) 256c094ef40SMatthew G. Knepley { 257c094ef40SMatthew G. Knepley Mat_Preallocator *p; 258c094ef40SMatthew G. Knepley 259c094ef40SMatthew G. Knepley PetscFunctionBegin; 2609566063dSJacob Faibussowitsch PetscCall(PetscNewLog(A, &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)); 285c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 286c094ef40SMatthew G. Knepley } 287