xref: /petsc/src/mat/impls/preallocator/matpreallocator.c (revision 146543f8e7ac722cd012c8183161b345d8cea8d7)
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;
9c094ef40SMatthew G. Knepley } Mat_Preallocator;
10c094ef40SMatthew G. Knepley 
11c094ef40SMatthew G. Knepley PetscErrorCode MatDestroy_Preallocator(Mat A)
12c094ef40SMatthew G. Knepley {
13c094ef40SMatthew G. Knepley   Mat_Preallocator *p = (Mat_Preallocator *) A->data;
14c094ef40SMatthew G. Knepley   PetscErrorCode    ierr;
15c094ef40SMatthew G. Knepley 
16c094ef40SMatthew G. Knepley   PetscFunctionBegin;
17c094ef40SMatthew G. Knepley   ierr = MatStashDestroy_Private(&A->stash);CHKERRQ(ierr);
18e8f14785SLisandro Dalcin   ierr = PetscHSetIJDestroy(&p->ht);CHKERRQ(ierr);
19c09129f1SStefano Zampini   ierr = PetscFree4(p->dnz, p->onz, p->dnzu, p->onzu);CHKERRQ(ierr);
20c094ef40SMatthew G. Knepley   ierr = PetscFree(A->data);CHKERRQ(ierr);
21f4259b30SLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject) A, NULL);CHKERRQ(ierr);
22c094ef40SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) A, "MatPreallocatorPreallocate_C", NULL);CHKERRQ(ierr);
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   PetscErrorCode    ierr;
31c094ef40SMatthew G. Knepley 
32c094ef40SMatthew G. Knepley   PetscFunctionBegin;
33c094ef40SMatthew G. Knepley   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
34c094ef40SMatthew G. Knepley   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
35c094ef40SMatthew G. Knepley   ierr = MatGetLocalSize(A, &m, NULL);CHKERRQ(ierr);
36e8f14785SLisandro Dalcin   ierr = PetscHSetIJCreate(&p->ht);CHKERRQ(ierr);
37c094ef40SMatthew G. Knepley   ierr = MatGetBlockSize(A, &bs);CHKERRQ(ierr);
388011973bSJunchao Zhang   /* Do not bother bstash since MatPreallocator does not implement MatSetValuesBlocked */
398011973bSJunchao Zhang   ierr = MatStashCreate_Private(PetscObjectComm((PetscObject) A), 1, &A->stash);CHKERRQ(ierr);
405dca1104SStefano Zampini   /* arrays are for blocked rows/cols */
415dca1104SStefano Zampini   mbs  = m/bs;
425dca1104SStefano Zampini   ierr = PetscCalloc4(mbs, &p->dnz, mbs, &p->onz, mbs, &p->dnzu, mbs, &p->onzu);CHKERRQ(ierr);
43c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
44c094ef40SMatthew G. Knepley }
45c094ef40SMatthew G. Knepley 
46c094ef40SMatthew G. Knepley PetscErrorCode MatSetValues_Preallocator(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
47c094ef40SMatthew G. Knepley {
48c094ef40SMatthew G. Knepley   Mat_Preallocator *p = (Mat_Preallocator *) A->data;
495dca1104SStefano Zampini   PetscInt          rStart, rEnd, r, cStart, cEnd, c, bs;
50c094ef40SMatthew G. Knepley   PetscErrorCode    ierr;
51c094ef40SMatthew G. Knepley 
52c094ef40SMatthew G. Knepley   PetscFunctionBegin;
535dca1104SStefano Zampini   ierr = MatGetBlockSize(A, &bs);CHKERRQ(ierr);
54c094ef40SMatthew G. Knepley   ierr = MatGetOwnershipRange(A, &rStart, &rEnd);CHKERRQ(ierr);
55c094ef40SMatthew G. Knepley   ierr = MatGetOwnershipRangeColumn(A, &cStart, &cEnd);CHKERRQ(ierr);
56c094ef40SMatthew G. Knepley   for (r = 0; r < m; ++r) {
57e8f14785SLisandro Dalcin     PetscHashIJKey key;
58e8f14785SLisandro Dalcin     PetscBool      missing;
59c094ef40SMatthew G. Knepley 
60e8f14785SLisandro Dalcin     key.i = rows[r];
61e8f14785SLisandro Dalcin     if (key.i < 0) continue;
62e8f14785SLisandro Dalcin     if ((key.i < rStart) || (key.i >= rEnd)) {
63e8f14785SLisandro Dalcin       ierr = MatStashValuesRow_Private(&A->stash, key.i, n, cols, values, PETSC_FALSE);CHKERRQ(ierr);
645dca1104SStefano Zampini     } else { /* Hash table is for blocked rows/cols */
655dca1104SStefano Zampini       key.i = rows[r]/bs;
66c094ef40SMatthew G. Knepley       for (c = 0; c < n; ++c) {
675dca1104SStefano Zampini         key.j = cols[c]/bs;
68e8f14785SLisandro Dalcin         if (key.j < 0) continue;
69e8f14785SLisandro Dalcin         ierr = PetscHSetIJQueryAdd(p->ht, key, &missing);CHKERRQ(ierr);
70c094ef40SMatthew G. Knepley         if (missing) {
715dca1104SStefano Zampini           if ((key.j >= cStart/bs) && (key.j < cEnd/bs)) {
725dca1104SStefano Zampini             ++p->dnz[key.i-rStart/bs];
735dca1104SStefano Zampini             if (key.j >= key.i) ++p->dnzu[key.i-rStart/bs];
74c09129f1SStefano Zampini           } else {
755dca1104SStefano Zampini             ++p->onz[key.i-rStart/bs];
765dca1104SStefano Zampini             if (key.j >= key.i) ++p->onzu[key.i-rStart/bs];
77c09129f1SStefano Zampini           }
78c094ef40SMatthew G. Knepley         }
79c094ef40SMatthew G. Knepley       }
80c094ef40SMatthew G. Knepley     }
81c094ef40SMatthew G. Knepley   }
82c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
83c094ef40SMatthew G. Knepley }
84c094ef40SMatthew G. Knepley 
85c094ef40SMatthew G. Knepley PetscErrorCode MatAssemblyBegin_Preallocator(Mat A, MatAssemblyType type)
86c094ef40SMatthew G. Knepley {
87c094ef40SMatthew G. Knepley   PetscInt       nstash, reallocs;
88c094ef40SMatthew G. Knepley   PetscErrorCode ierr;
89c094ef40SMatthew G. Knepley 
90c094ef40SMatthew G. Knepley   PetscFunctionBegin;
91c094ef40SMatthew G. Knepley   ierr = MatStashScatterBegin_Private(A, &A->stash, A->rmap->range);CHKERRQ(ierr);
92c094ef40SMatthew G. Knepley   ierr = MatStashGetInfo_Private(&A->stash, &nstash, &reallocs);CHKERRQ(ierr);
93c094ef40SMatthew G. Knepley   ierr = PetscInfo2(A, "Stash has %D entries, uses %D mallocs.\n", nstash, reallocs);CHKERRQ(ierr);
94c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
95c094ef40SMatthew G. Knepley }
96c094ef40SMatthew G. Knepley 
97c094ef40SMatthew G. Knepley PetscErrorCode MatAssemblyEnd_Preallocator(Mat A, MatAssemblyType type)
98c094ef40SMatthew G. Knepley {
99c094ef40SMatthew G. Knepley   PetscScalar      *val;
100c094ef40SMatthew G. Knepley   PetscInt         *row, *col;
101c094ef40SMatthew G. Knepley   PetscInt         i, j, rstart, ncols, flg;
102c094ef40SMatthew G. Knepley   PetscMPIInt      n;
103f8f6e9aeSStefano Zampini   Mat_Preallocator *p = (Mat_Preallocator *) A->data;
104c094ef40SMatthew G. Knepley   PetscErrorCode   ierr;
105c094ef40SMatthew G. Knepley 
106c094ef40SMatthew G. Knepley   PetscFunctionBegin;
107f8f6e9aeSStefano Zampini   p->nooffproc = PETSC_TRUE;
108c094ef40SMatthew G. Knepley   while (1) {
109c094ef40SMatthew G. Knepley     ierr = MatStashScatterGetMesg_Private(&A->stash, &n, &row, &col, &val, &flg);CHKERRQ(ierr);
110f8f6e9aeSStefano Zampini     if (flg) p->nooffproc = PETSC_FALSE;
111c094ef40SMatthew G. Knepley     if (!flg) break;
112c094ef40SMatthew G. Knepley 
113c094ef40SMatthew G. Knepley     for (i = 0; i < n;) {
114c094ef40SMatthew G. Knepley       /* Now identify the consecutive vals belonging to the same row */
115c094ef40SMatthew G. Knepley       for (j = i, rstart = row[j]; j < n; j++) {
116c094ef40SMatthew G. Knepley         if (row[j] != rstart) break;
117c094ef40SMatthew G. Knepley       }
118c094ef40SMatthew G. Knepley       if (j < n) ncols = j-i;
119c094ef40SMatthew G. Knepley       else       ncols = n-i;
120c094ef40SMatthew G. Knepley       /* Now assemble all these values with a single function call */
121c094ef40SMatthew G. Knepley       ierr = MatSetValues_Preallocator(A, 1, row+i, ncols, col+i, val+i, INSERT_VALUES);CHKERRQ(ierr);
122c094ef40SMatthew G. Knepley       i = j;
123c094ef40SMatthew G. Knepley     }
124c094ef40SMatthew G. Knepley   }
125c094ef40SMatthew G. Knepley   ierr = MatStashScatterEnd_Private(&A->stash);CHKERRQ(ierr);
126820f2d46SBarry Smith   ierr = MPIU_Allreduce(MPI_IN_PLACE,&p->nooffproc,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRMPI(ierr);
127c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
128c094ef40SMatthew G. Knepley }
129c094ef40SMatthew G. Knepley 
130c094ef40SMatthew G. Knepley PetscErrorCode MatView_Preallocator(Mat A, PetscViewer viewer)
131c094ef40SMatthew G. Knepley {
132c094ef40SMatthew G. Knepley   PetscFunctionBegin;
133c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
134c094ef40SMatthew G. Knepley }
135c094ef40SMatthew G. Knepley 
136c094ef40SMatthew G. Knepley PetscErrorCode MatSetOption_Preallocator(Mat A, MatOption op, PetscBool flg)
137c094ef40SMatthew G. Knepley {
138c094ef40SMatthew G. Knepley   PetscFunctionBegin;
139c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
140c094ef40SMatthew G. Knepley }
141c094ef40SMatthew G. Knepley 
142c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate_Preallocator(Mat mat, PetscBool fill, Mat A)
143c094ef40SMatthew G. Knepley {
144c094ef40SMatthew G. Knepley   Mat_Preallocator *p = (Mat_Preallocator *) mat->data;
145c094ef40SMatthew G. Knepley   PetscInt          bs;
146c094ef40SMatthew G. Knepley   PetscErrorCode    ierr;
147c094ef40SMatthew G. Knepley 
148c094ef40SMatthew G. Knepley   PetscFunctionBegin;
149c094ef40SMatthew G. Knepley   ierr = MatGetBlockSize(mat, &bs);CHKERRQ(ierr);
150c09129f1SStefano Zampini   ierr = MatXAIJSetPreallocation(A, bs, p->dnz, p->onz, p->dnzu, p->onzu);CHKERRQ(ierr);
151050c3c49SStefano Zampini   ierr = MatSetUp(A);CHKERRQ(ierr);
152c094ef40SMatthew G. Knepley   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);CHKERRQ(ierr);
153f8f6e9aeSStefano Zampini   ierr = MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, p->nooffproc);CHKERRQ(ierr);
154380bf85aSDave May   if (fill) {
155380bf85aSDave May     PetscHashIter  hi;
156380bf85aSDave May     PetscHashIJKey key;
157380bf85aSDave May     PetscScalar    *zeros;
158*146543f8SJed Brown     PetscInt       n,maxrow=1,*rows,*cols;
159380bf85aSDave May 
160*146543f8SJed Brown     ierr = PetscHSetIJGetSize(p->ht,&n);CHKERRQ(ierr);
161*146543f8SJed Brown     ierr = PetscMalloc2(n,&rows,n,&cols);CHKERRQ(ierr);
162380bf85aSDave May     PetscHashIterBegin(p->ht,hi);
163*146543f8SJed Brown     for (PetscInt i=0; !PetscHashIterAtEnd(p->ht,hi); i++) {
164380bf85aSDave May       PetscHashIterGetKey(p->ht,hi,key);
165*146543f8SJed Brown       rows[i] = key.i;
166*146543f8SJed Brown       cols[i] = key.j;
167380bf85aSDave May       PetscHashIterNext(p->ht,hi);
168*146543f8SJed Brown     }
169*146543f8SJed Brown     ierr = PetscHSetIJDestroy(&p->ht);CHKERRQ(ierr);
170*146543f8SJed Brown 
171*146543f8SJed Brown     ierr = PetscCalloc1(maxrow*bs*bs,&zeros);CHKERRQ(ierr);
172*146543f8SJed Brown     ierr = PetscSortIntWithArray(n,rows,cols);CHKERRQ(ierr);
173*146543f8SJed Brown     for (PetscInt start=0,end=1; start<n; start=end,end++) {
174*146543f8SJed Brown       while (end < n && rows[end] == rows[start]) end++;
175*146543f8SJed Brown       ierr = PetscSortInt(end-start,&cols[start]);CHKERRQ(ierr);
176*146543f8SJed Brown       if (maxrow < end-start) {
177*146543f8SJed Brown         maxrow = 2*(end - start);
178*146543f8SJed Brown         ierr = PetscRealloc(maxrow*bs*bs*sizeof(zeros[0]),&zeros);CHKERRQ(ierr);
179*146543f8SJed Brown         ierr = PetscMemzero(zeros, maxrow*bs*bs*sizeof(zeros[0]));CHKERRQ(ierr);
180*146543f8SJed Brown       }
181*146543f8SJed Brown       ierr = MatSetValuesBlocked(A, 1, &rows[start], end-start, &cols[start], zeros, INSERT_VALUES);CHKERRQ(ierr);
182380bf85aSDave May     }
183380bf85aSDave May     ierr = PetscFree(zeros);CHKERRQ(ierr);
184*146543f8SJed Brown     ierr = PetscFree2(rows,cols);CHKERRQ(ierr);
185380bf85aSDave May 
186380bf85aSDave May     ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
187380bf85aSDave May     ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
188380bf85aSDave May   }
189c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
190c094ef40SMatthew G. Knepley }
191c094ef40SMatthew G. Knepley 
192c094ef40SMatthew G. Knepley /*@
193380bf85aSDave May   MatPreallocatorPreallocate - Preallocates the A matrix, using information from mat, optionally filling A with zeros
194c094ef40SMatthew G. Knepley 
195c094ef40SMatthew G. Knepley   Input Parameter:
196c094ef40SMatthew G. Knepley + mat  - the preallocator
197380bf85aSDave May . fill - fill the matrix with zeros
198380bf85aSDave May - A    - the matrix to be preallocated
199c094ef40SMatthew G. Knepley 
200380bf85aSDave May   Notes:
201380bf85aSDave May   This Mat implementation provides a helper utility to define the correct
202380bf85aSDave May   preallocation data for a given nonzero structure. Use this object like a
203380bf85aSDave May   regular matrix, e.g. loop over the nonzero structure of the matrix and
204380bf85aSDave May   call MatSetValues() or MatSetValuesBlocked() to indicate the nonzero locations.
205380bf85aSDave May   The matrix entires provided to MatSetValues() will be ignored, it only uses
206380bf85aSDave May   the row / col indices provided to determine the information required to be
207380bf85aSDave May   passed to MatXAIJSetPreallocation(). Once you have looped over the nonzero
208380bf85aSDave May   structure, you must call MatAssemblyBegin(), MatAssemblyEnd() on mat.
209380bf85aSDave May 
210380bf85aSDave May   After you have assembled the preallocator matrix (mat), call MatPreallocatorPreallocate()
211380bf85aSDave May   to define the preallocation information on the matrix (A). Setting the parameter
212380bf85aSDave May   fill = PETSC_TRUE will insert zeros into the matrix A. Internally MatPreallocatorPreallocate()
213380bf85aSDave May   will call MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
214c094ef40SMatthew G. Knepley 
215c094ef40SMatthew G. Knepley   Level: advanced
216c094ef40SMatthew G. Knepley 
217c094ef40SMatthew G. Knepley .seealso: MATPREALLOCATOR
218c094ef40SMatthew G. Knepley @*/
219c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A)
220c094ef40SMatthew G. Knepley {
221c094ef40SMatthew G. Knepley   PetscErrorCode ierr;
222c094ef40SMatthew G. Knepley 
223c094ef40SMatthew G. Knepley   PetscFunctionBegin;
224c094ef40SMatthew G. Knepley   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
225c094ef40SMatthew G. Knepley   PetscValidHeaderSpecific(A,   MAT_CLASSID, 3);
226c094ef40SMatthew G. Knepley   ierr = PetscUseMethod(mat, "MatPreallocatorPreallocate_C", (Mat,PetscBool,Mat),(mat,fill,A));CHKERRQ(ierr);
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:
234c094ef40SMatthew G. Knepley .  MatSetValues()
235c094ef40SMatthew G. Knepley 
236c094ef40SMatthew G. Knepley    Options Database Keys:
237c094ef40SMatthew G. Knepley . -mat_type preallocator - sets the matrix type to "preallocator" during a call to MatSetFromOptions()
238c094ef40SMatthew G. Knepley 
239c094ef40SMatthew G. Knepley   Level: advanced
240c094ef40SMatthew G. Knepley 
241c094ef40SMatthew G. Knepley .seealso: Mat
242c094ef40SMatthew G. Knepley 
243c094ef40SMatthew G. Knepley M*/
244c094ef40SMatthew G. Knepley 
245c094ef40SMatthew G. Knepley PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A)
246c094ef40SMatthew G. Knepley {
247c094ef40SMatthew G. Knepley   Mat_Preallocator *p;
248c094ef40SMatthew G. Knepley   PetscErrorCode    ierr;
249c094ef40SMatthew G. Knepley 
250c094ef40SMatthew G. Knepley   PetscFunctionBegin;
251c094ef40SMatthew G. Knepley   ierr = PetscNewLog(A, &p);CHKERRQ(ierr);
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;
259c094ef40SMatthew G. Knepley 
260c094ef40SMatthew G. Knepley   /* matrix ops */
261c094ef40SMatthew G. Knepley   ierr = PetscMemzero(A->ops, sizeof(struct _MatOps));CHKERRQ(ierr);
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 */
273c094ef40SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator);CHKERRQ(ierr);
274c094ef40SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) A, MATPREALLOCATOR);CHKERRQ(ierr);
275c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
276c094ef40SMatthew G. Knepley }
277