xref: /petsc/src/mat/impls/preallocator/matpreallocator.c (revision d8d19677bbccf95218448bee62e6b87f4513e133)
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;
149880e7892SJed Brown   if (!fill) {ierr = PetscHSetIJDestroy(&p->ht);CHKERRQ(ierr);}
150c094ef40SMatthew G. Knepley   ierr = MatGetBlockSize(mat, &bs);CHKERRQ(ierr);
151c09129f1SStefano Zampini   ierr = MatXAIJSetPreallocation(A, bs, p->dnz, p->onz, p->dnzu, p->onzu);CHKERRQ(ierr);
152050c3c49SStefano Zampini   ierr = MatSetUp(A);CHKERRQ(ierr);
153c094ef40SMatthew G. Knepley   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);CHKERRQ(ierr);
154f8f6e9aeSStefano Zampini   ierr = MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, p->nooffproc);CHKERRQ(ierr);
155380bf85aSDave May   if (fill) {
156380bf85aSDave May     PetscHashIter  hi;
157380bf85aSDave May     PetscHashIJKey key;
158380bf85aSDave May     PetscScalar    *zeros;
159880e7892SJed Brown     PetscInt       n,maxrow=1,*cols,rStart,rEnd,*rowstarts;
160380bf85aSDave May 
161880e7892SJed Brown     ierr = MatGetOwnershipRange(A, &rStart, &rEnd);CHKERRQ(ierr);
162880e7892SJed Brown     // Ownership range is in terms of scalar entries, but we deal with blocks
163880e7892SJed Brown     rStart /= bs;
164880e7892SJed Brown     rEnd /= bs;
165146543f8SJed Brown     ierr = PetscHSetIJGetSize(p->ht,&n);CHKERRQ(ierr);
166880e7892SJed Brown     ierr = PetscMalloc2(n,&cols,rEnd-rStart+1,&rowstarts);CHKERRQ(ierr);
167880e7892SJed Brown     rowstarts[0] = 0;
168880e7892SJed Brown     for (PetscInt i=0; i<rEnd-rStart; i++) {
169880e7892SJed Brown       rowstarts[i+1] = rowstarts[i] + p->dnz[i] + p->onz[i];
170880e7892SJed Brown       maxrow = PetscMax(maxrow, p->dnz[i] + p->onz[i]);
171880e7892SJed Brown     }
172880e7892SJed Brown     if (rowstarts[rEnd-rStart] != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hash claims %D entries, but dnz+onz counts %D",n,rowstarts[rEnd-rStart]);
173880e7892SJed Brown 
174380bf85aSDave May     PetscHashIterBegin(p->ht,hi);
175146543f8SJed Brown     for (PetscInt i=0; !PetscHashIterAtEnd(p->ht,hi); i++) {
176380bf85aSDave May       PetscHashIterGetKey(p->ht,hi,key);
177880e7892SJed Brown       PetscInt lrow = key.i - rStart;
178880e7892SJed Brown       cols[rowstarts[lrow]] = key.j;
179880e7892SJed Brown       rowstarts[lrow]++;
180380bf85aSDave May       PetscHashIterNext(p->ht,hi);
181146543f8SJed Brown     }
182146543f8SJed Brown     ierr = PetscHSetIJDestroy(&p->ht);CHKERRQ(ierr);
183146543f8SJed Brown 
184146543f8SJed Brown     ierr = PetscCalloc1(maxrow*bs*bs,&zeros);CHKERRQ(ierr);
185880e7892SJed Brown     for (PetscInt i=0; i<rEnd-rStart; i++) {
186880e7892SJed Brown       PetscInt grow = rStart + i;
187880e7892SJed Brown       PetscInt end = rowstarts[i], start = end - p->dnz[i] - p->onz[i];
188146543f8SJed Brown       ierr = PetscSortInt(end-start,&cols[start]);CHKERRQ(ierr);
189880e7892SJed Brown       ierr = MatSetValuesBlocked(A, 1, &grow, end-start, &cols[start], zeros, INSERT_VALUES);CHKERRQ(ierr);
190380bf85aSDave May     }
191380bf85aSDave May     ierr = PetscFree(zeros);CHKERRQ(ierr);
192880e7892SJed Brown     ierr = PetscFree2(cols,rowstarts);CHKERRQ(ierr);
193380bf85aSDave May 
194380bf85aSDave May     ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
195380bf85aSDave May     ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
196380bf85aSDave May   }
197c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
198c094ef40SMatthew G. Knepley }
199c094ef40SMatthew G. Knepley 
200c094ef40SMatthew G. Knepley /*@
201380bf85aSDave May   MatPreallocatorPreallocate - Preallocates the A matrix, using information from mat, optionally filling A with zeros
202c094ef40SMatthew G. Knepley 
203*d8d19677SJose E. Roman   Input Parameters:
204c094ef40SMatthew G. Knepley + mat  - the preallocator
205380bf85aSDave May . fill - fill the matrix with zeros
206380bf85aSDave May - A    - the matrix to be preallocated
207c094ef40SMatthew G. Knepley 
208380bf85aSDave May   Notes:
209380bf85aSDave May   This Mat implementation provides a helper utility to define the correct
210380bf85aSDave May   preallocation data for a given nonzero structure. Use this object like a
211380bf85aSDave May   regular matrix, e.g. loop over the nonzero structure of the matrix and
212380bf85aSDave May   call MatSetValues() or MatSetValuesBlocked() to indicate the nonzero locations.
213a5b23f4aSJose E. Roman   The matrix entries provided to MatSetValues() will be ignored, it only uses
214380bf85aSDave May   the row / col indices provided to determine the information required to be
215380bf85aSDave May   passed to MatXAIJSetPreallocation(). Once you have looped over the nonzero
216380bf85aSDave May   structure, you must call MatAssemblyBegin(), MatAssemblyEnd() on mat.
217380bf85aSDave May 
218380bf85aSDave May   After you have assembled the preallocator matrix (mat), call MatPreallocatorPreallocate()
219380bf85aSDave May   to define the preallocation information on the matrix (A). Setting the parameter
220380bf85aSDave May   fill = PETSC_TRUE will insert zeros into the matrix A. Internally MatPreallocatorPreallocate()
221380bf85aSDave May   will call MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
222c094ef40SMatthew G. Knepley 
223c094ef40SMatthew G. Knepley   Level: advanced
224c094ef40SMatthew G. Knepley 
225c094ef40SMatthew G. Knepley .seealso: MATPREALLOCATOR
226c094ef40SMatthew G. Knepley @*/
227c094ef40SMatthew G. Knepley PetscErrorCode MatPreallocatorPreallocate(Mat mat, PetscBool fill, Mat A)
228c094ef40SMatthew G. Knepley {
229c094ef40SMatthew G. Knepley   PetscErrorCode ierr;
230c094ef40SMatthew G. Knepley 
231c094ef40SMatthew G. Knepley   PetscFunctionBegin;
232c094ef40SMatthew G. Knepley   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
233c094ef40SMatthew G. Knepley   PetscValidHeaderSpecific(A,   MAT_CLASSID, 3);
234c094ef40SMatthew G. Knepley   ierr = PetscUseMethod(mat, "MatPreallocatorPreallocate_C", (Mat,PetscBool,Mat),(mat,fill,A));CHKERRQ(ierr);
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:
242c094ef40SMatthew G. Knepley .  MatSetValues()
243c094ef40SMatthew G. Knepley 
244c094ef40SMatthew G. Knepley    Options Database Keys:
245c094ef40SMatthew G. Knepley . -mat_type preallocator - sets the matrix type to "preallocator" during a call to MatSetFromOptions()
246c094ef40SMatthew G. Knepley 
247c094ef40SMatthew G. Knepley   Level: advanced
248c094ef40SMatthew G. Knepley 
249c094ef40SMatthew G. Knepley .seealso: Mat
250c094ef40SMatthew G. Knepley 
251c094ef40SMatthew G. Knepley M*/
252c094ef40SMatthew G. Knepley 
253c094ef40SMatthew G. Knepley PETSC_EXTERN PetscErrorCode MatCreate_Preallocator(Mat A)
254c094ef40SMatthew G. Knepley {
255c094ef40SMatthew G. Knepley   Mat_Preallocator *p;
256c094ef40SMatthew G. Knepley   PetscErrorCode    ierr;
257c094ef40SMatthew G. Knepley 
258c094ef40SMatthew G. Knepley   PetscFunctionBegin;
259c094ef40SMatthew G. Knepley   ierr = PetscNewLog(A, &p);CHKERRQ(ierr);
260c094ef40SMatthew G. Knepley   A->data = (void *) p;
261c094ef40SMatthew G. Knepley 
262c094ef40SMatthew G. Knepley   p->ht   = NULL;
263c094ef40SMatthew G. Knepley   p->dnz  = NULL;
264c094ef40SMatthew G. Knepley   p->onz  = NULL;
265c09129f1SStefano Zampini   p->dnzu = NULL;
266c09129f1SStefano Zampini   p->onzu = NULL;
267c094ef40SMatthew G. Knepley 
268c094ef40SMatthew G. Knepley   /* matrix ops */
269c094ef40SMatthew G. Knepley   ierr = PetscMemzero(A->ops, sizeof(struct _MatOps));CHKERRQ(ierr);
270c09129f1SStefano Zampini 
271c094ef40SMatthew G. Knepley   A->ops->destroy       = MatDestroy_Preallocator;
272c094ef40SMatthew G. Knepley   A->ops->setup         = MatSetUp_Preallocator;
273c094ef40SMatthew G. Knepley   A->ops->setvalues     = MatSetValues_Preallocator;
274c094ef40SMatthew G. Knepley   A->ops->assemblybegin = MatAssemblyBegin_Preallocator;
275c094ef40SMatthew G. Knepley   A->ops->assemblyend   = MatAssemblyEnd_Preallocator;
276c094ef40SMatthew G. Knepley   A->ops->view          = MatView_Preallocator;
277c094ef40SMatthew G. Knepley   A->ops->setoption     = MatSetOption_Preallocator;
2785dca1104SStefano Zampini   A->ops->setblocksizes = MatSetBlockSizes_Default; /* once set, user is not allowed to change the block sizes */
279c094ef40SMatthew G. Knepley 
280c094ef40SMatthew G. Knepley   /* special MATPREALLOCATOR functions */
281c094ef40SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) A, "MatPreallocatorPreallocate_C", MatPreallocatorPreallocate_Preallocator);CHKERRQ(ierr);
282c094ef40SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) A, MATPREALLOCATOR);CHKERRQ(ierr);
283c094ef40SMatthew G. Knepley   PetscFunctionReturn(0);
284c094ef40SMatthew G. Knepley }
285