xref: /petsc/src/mat/impls/preallocator/matpreallocator.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
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