xref: /petsc/src/mat/impls/preallocator/matpreallocator.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
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 
129371c9d4SSatish 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 
259371c9d4SSatish 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 
439371c9d4SSatish 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 
809371c9d4SSatish 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 
909371c9d4SSatish 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 
1219371c9d4SSatish Balay PetscErrorCode MatView_Preallocator(Mat A, PetscViewer viewer) {
122c094ef40SMatthew G. Knepley   PetscFunctionBegin;
123c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
124c094ef40SMatthew G. Knepley }
125c094ef40SMatthew G. Knepley 
1269371c9d4SSatish 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 
1319371c9d4SSatish 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 /*@
19111a5261eSBarry Smith   MatPreallocatorPreallocate - Preallocates the A matrix, using information from a `MATPREALLOCATOR` mat, optionally filling A with zeros
192c094ef40SMatthew G. Knepley 
193d8d19677SJose E. Roman   Input Parameters:
19411a5261eSBarry Smith + mat  - the `MATPREALLOCATOR` preallocator matrix
195380bf85aSDave May . fill - fill the matrix with zeros
196380bf85aSDave May - A    - the matrix to be preallocated
197c094ef40SMatthew G. Knepley 
198380bf85aSDave May   Notes:
19911a5261eSBarry Smith   This `MatType` 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
20211a5261eSBarry Smith   call `MatSetValues()` or `MatSetValuesBlocked()` to indicate the nonzero locations.
20311a5261eSBarry Smith   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
20511a5261eSBarry Smith   passed to `MatXAIJSetPreallocation()`. Once you have looped over the nonzero
20611a5261eSBarry Smith   structure, you must call `MatAssemblyBegin()`, `MatAssemblyEnd()` on mat.
207380bf85aSDave May 
20811a5261eSBarry Smith   After you have assembled the preallocator matrix (mat), call `MatPreallocatorPreallocate()`
209380bf85aSDave May   to define the preallocation information on the matrix (A). Setting the parameter
21011a5261eSBarry Smith   fill = PETSC_TRUE will insert zeros into the matrix A. Internally `MatPreallocatorPreallocate()`
21111a5261eSBarry Smith   will call `MatSetOption`(A, `MAT_NEW_NONZERO_ALLOCATION_ERR`, `PETSC_TRUE`);
212c094ef40SMatthew G. Knepley 
21311a5261eSBarry Smith   This function may only be called once for a given `MATPREALLOCATOR` object. If
21411a5261eSBarry Smith   multiple `Mat`s need to be preallocated, consider using `MatDuplicate()` after
215fcc385faSPatrick Sanan   this function.
216fcc385faSPatrick Sanan 
217c094ef40SMatthew G. Knepley   Level: advanced
218c094ef40SMatthew G. Knepley 
21911a5261eSBarry Smith .seealso: `MATPREALLOCATOR`, `MatXAIJSetPreallocation()`
220c094ef40SMatthew G. Knepley @*/
2219371c9d4SSatish 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:
23911a5261eSBarry Smith . -mat_type preallocator - sets the matrix type to `MATPREALLOCATOR` during a call to `MatSetFromOptions()`
240c094ef40SMatthew G. Knepley 
241c094ef40SMatthew G. Knepley   Level: advanced
242c094ef40SMatthew G. Knepley 
24311a5261eSBarry Smith .seealso: `MATPREALLOCATOR`, `Mat`, `MatPreallocatorPreallocate()`
244c094ef40SMatthew G. Knepley M*/
245c094ef40SMatthew G. Knepley 
2469371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A) {
247c094ef40SMatthew G. Knepley   Mat_Preallocator *p;
248c094ef40SMatthew G. Knepley 
249c094ef40SMatthew G. Knepley   PetscFunctionBegin;
250*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&p));
251c094ef40SMatthew G. Knepley   A->data = (void *)p;
252c094ef40SMatthew G. Knepley 
253c094ef40SMatthew G. Knepley   p->ht   = NULL;
254c094ef40SMatthew G. Knepley   p->dnz  = NULL;
255c094ef40SMatthew G. Knepley   p->onz  = NULL;
256c09129f1SStefano Zampini   p->dnzu = NULL;
257c09129f1SStefano Zampini   p->onzu = NULL;
258fcc385faSPatrick Sanan   p->used = PETSC_FALSE;
259c094ef40SMatthew G. Knepley 
260c094ef40SMatthew G. Knepley   /* matrix ops */
2619566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
262c09129f1SStefano Zampini 
263c094ef40SMatthew G. Knepley   A->ops->destroy       = MatDestroy_Preallocator;
264c094ef40SMatthew G. Knepley   A->ops->setup         = MatSetUp_Preallocator;
265c094ef40SMatthew G. Knepley   A->ops->setvalues     = MatSetValues_Preallocator;
266c094ef40SMatthew G. Knepley   A->ops->assemblybegin = MatAssemblyBegin_Preallocator;
267c094ef40SMatthew G. Knepley   A->ops->assemblyend   = MatAssemblyEnd_Preallocator;
268c094ef40SMatthew G. Knepley   A->ops->view          = MatView_Preallocator;
269c094ef40SMatthew G. Knepley   A->ops->setoption     = MatSetOption_Preallocator;
2705dca1104SStefano Zampini   A->ops->setblocksizes = MatSetBlockSizes_Default; /* once set, user is not allowed to change the block sizes */
271c094ef40SMatthew G. Knepley 
272c094ef40SMatthew G. Knepley   /* special MATPREALLOCATOR functions */
2739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator));
2749566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATPREALLOCATOR));
275c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
276c094ef40SMatthew G. Knepley }
277