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