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)); 1221c2dc1cbSBarry Smith PetscCall(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)); 151380bf85aSDave May if (fill) { 152*a6f8f0ebSPatrick 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 } 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)); 193*a6f8f0ebSPatrick Sanan PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_FALSE)); 194380bf85aSDave May } 195c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 196c094ef40SMatthew G. Knepley } 197c094ef40SMatthew G. Knepley 198c094ef40SMatthew G. Knepley /*@ 199380bf85aSDave May MatPreallocatorPreallocate - Preallocates the A matrix, using information from mat, optionally filling A with zeros 200c094ef40SMatthew G. Knepley 201d8d19677SJose E. Roman Input Parameters: 202c094ef40SMatthew G. Knepley + mat - the preallocator 203380bf85aSDave May . fill - fill the matrix with zeros 204380bf85aSDave May - A - the matrix to be preallocated 205c094ef40SMatthew G. Knepley 206380bf85aSDave May Notes: 207380bf85aSDave May This Mat 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 210380bf85aSDave May call MatSetValues() or MatSetValuesBlocked() to indicate the nonzero locations. 211a5b23f4aSJose E. Roman 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 213380bf85aSDave May passed to MatXAIJSetPreallocation(). Once you have looped over the nonzero 214380bf85aSDave May structure, you must call MatAssemblyBegin(), MatAssemblyEnd() on mat. 215380bf85aSDave May 216380bf85aSDave May After you have assembled the preallocator matrix (mat), call MatPreallocatorPreallocate() 217380bf85aSDave May to define the preallocation information on the matrix (A). Setting the parameter 218380bf85aSDave May fill = PETSC_TRUE will insert zeros into the matrix A. Internally MatPreallocatorPreallocate() 219380bf85aSDave May will call MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE); 220c094ef40SMatthew G. Knepley 221fcc385faSPatrick Sanan This function may only be called once for a given MatPreallocator object. If 222fcc385faSPatrick Sanan multiple Mats need to be preallocated, consider using MatDuplicate() after 223fcc385faSPatrick Sanan this function. 224fcc385faSPatrick Sanan 225c094ef40SMatthew G. Knepley Level: advanced 226c094ef40SMatthew G. Knepley 227c094ef40SMatthew G. Knepley .seealso: MATPREALLOCATOR 228c094ef40SMatthew G. Knepley @*/ 229c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A) 230c094ef40SMatthew G. Knepley { 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)); 236c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 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: 248c094ef40SMatthew G. Knepley . -mat_type preallocator - sets the matrix type to "preallocator" during a call to MatSetFromOptions() 249c094ef40SMatthew G. Knepley 250c094ef40SMatthew G. Knepley Level: advanced 251c094ef40SMatthew G. Knepley 252c74f52fcSPatrick Sanan .seealso: Mat, MatPreallocatorPreallocate() 253c094ef40SMatthew G. Knepley 254c094ef40SMatthew G. Knepley M*/ 255c094ef40SMatthew G. Knepley 256c094ef40SMatthew G. Knepley PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A) 257c094ef40SMatthew G. Knepley { 258c094ef40SMatthew G. Knepley Mat_Preallocator *p; 259c094ef40SMatthew G. Knepley 260c094ef40SMatthew G. Knepley PetscFunctionBegin; 2619566063dSJacob Faibussowitsch PetscCall(PetscNewLog(A, &p)); 262c094ef40SMatthew G. Knepley A->data = (void *) p; 263c094ef40SMatthew G. Knepley 264c094ef40SMatthew G. Knepley p->ht = NULL; 265c094ef40SMatthew G. Knepley p->dnz = NULL; 266c094ef40SMatthew G. Knepley p->onz = NULL; 267c09129f1SStefano Zampini p->dnzu = NULL; 268c09129f1SStefano Zampini p->onzu = NULL; 269fcc385faSPatrick Sanan p->used = PETSC_FALSE; 270c094ef40SMatthew G. Knepley 271c094ef40SMatthew G. Knepley /* matrix ops */ 2729566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps))); 273c09129f1SStefano Zampini 274c094ef40SMatthew G. Knepley A->ops->destroy = MatDestroy_Preallocator; 275c094ef40SMatthew G. Knepley A->ops->setup = MatSetUp_Preallocator; 276c094ef40SMatthew G. Knepley A->ops->setvalues = MatSetValues_Preallocator; 277c094ef40SMatthew G. Knepley A->ops->assemblybegin = MatAssemblyBegin_Preallocator; 278c094ef40SMatthew G. Knepley A->ops->assemblyend = MatAssemblyEnd_Preallocator; 279c094ef40SMatthew G. Knepley A->ops->view = MatView_Preallocator; 280c094ef40SMatthew G. Knepley A->ops->setoption = MatSetOption_Preallocator; 2815dca1104SStefano Zampini A->ops->setblocksizes = MatSetBlockSizes_Default; /* once set, user is not allowed to change the block sizes */ 282c094ef40SMatthew G. Knepley 283c094ef40SMatthew G. Knepley /* special MATPREALLOCATOR functions */ 2849566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject) A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator)); 2859566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject) A, MATPREALLOCATOR)); 286c094ef40SMatthew G. Knepley PetscFunctionReturn(0); 287c094ef40SMatthew G. Knepley } 288