xref: /petsc/src/dm/impls/da/hypre/mhyp.c (revision 2205254efee3a00a594e5e2a3a70f74dcb40bc03) !
1 
2 /*
3     Creates hypre ijmatrix from PETSc matrix
4 */
5 #include <petscsys.h>
6 #include <petsc-private/matimpl.h>
7 #include <petscdmda.h>                /*I "petscdmda.h" I*/
8 #include <../src/dm/impls/da/hypre/mhyp.h>
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "MatHYPRE_IJMatrixPreallocate"
12 PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat A_d, Mat A_o,HYPRE_IJMatrix ij)
13 {
14   PetscErrorCode ierr;
15   PetscInt       i,n_d,n_o;
16   const PetscInt *ia_d,*ia_o;
17   PetscBool      done_d=PETSC_FALSE,done_o=PETSC_FALSE;
18   PetscInt       *nnz_d=PETSC_NULL,*nnz_o=PETSC_NULL;
19 
20   PetscFunctionBegin;
21   if (A_d) { /* determine number of nonzero entries in local diagonal part */
22     ierr = MatGetRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);CHKERRQ(ierr);
23     if (done_d) {
24       ierr = PetscMalloc(n_d*sizeof(PetscInt),&nnz_d);CHKERRQ(ierr);
25       for (i=0; i<n_d; i++) {
26         nnz_d[i] = ia_d[i+1] - ia_d[i];
27       }
28     }
29     ierr = MatRestoreRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);CHKERRQ(ierr);
30   }
31   if (A_o) { /* determine number of nonzero entries in local off-diagonal part */
32     ierr = MatGetRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);CHKERRQ(ierr);
33     if (done_o) {
34       ierr = PetscMalloc(n_o*sizeof(PetscInt),&nnz_o);CHKERRQ(ierr);
35       for (i=0; i<n_o; i++) {
36         nnz_o[i] = ia_o[i+1] - ia_o[i];
37       }
38     }
39     ierr = MatRestoreRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);CHKERRQ(ierr);
40   }
41   if (done_d) {    /* set number of nonzeros in HYPRE IJ matrix */
42     if (!done_o) { /* only diagonal part */
43       ierr = PetscMalloc(n_d*sizeof(PetscInt),&nnz_o);CHKERRQ(ierr);
44       for (i=0; i<n_d; i++) {
45         nnz_o[i] = 0;
46       }
47     }
48     PetscStackCallStandard(HYPRE_IJMatrixSetDiagOffdSizes,(ij,nnz_d,nnz_o));
49     ierr = PetscFree(nnz_d);CHKERRQ(ierr);
50     ierr = PetscFree(nnz_o);CHKERRQ(ierr);
51   }
52   PetscFunctionReturn(0);
53 }
54 
55 #undef __FUNCT__
56 #define __FUNCT__ "MatHYPRE_IJMatrixCreate"
57 PetscErrorCode MatHYPRE_IJMatrixCreate(Mat A,HYPRE_IJMatrix *ij)
58 {
59   PetscErrorCode ierr;
60   PetscInt       rstart,rend,cstart,cend;
61 
62   PetscFunctionBegin;
63   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
64   PetscValidType(A,1);
65   PetscValidPointer(ij,2);
66   ierr   = MatSetUp(A);CHKERRQ(ierr);
67   rstart = A->rmap->rstart;
68   rend   = A->rmap->rend;
69   cstart = A->cmap->rstart;
70   cend   = A->cmap->rend;
71   PetscStackCallStandard(HYPRE_IJMatrixCreate,(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij));
72   PetscStackCallStandard(HYPRE_IJMatrixSetObjectType,(*ij,HYPRE_PARCSR));
73   {
74     PetscBool      same;
75     Mat            A_d,A_o;
76     const PetscInt *colmap;
77     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&same);CHKERRQ(ierr);
78     if (same) {
79       ierr = MatMPIAIJGetSeqAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr);
80       ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);CHKERRQ(ierr);
81       PetscFunctionReturn(0);
82     }
83     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&same);CHKERRQ(ierr);
84     if (same) {
85       ierr = MatMPIBAIJGetSeqBAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr);
86       ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);CHKERRQ(ierr);
87       PetscFunctionReturn(0);
88     }
89     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&same);CHKERRQ(ierr);
90     if (same) {
91       ierr = MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);CHKERRQ(ierr);
92       PetscFunctionReturn(0);
93     }
94     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQBAIJ,&same);CHKERRQ(ierr);
95     if (same) {
96       ierr = MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);CHKERRQ(ierr);
97       PetscFunctionReturn(0);
98     }
99   }
100   PetscFunctionReturn(0);
101 }
102 
103 extern PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat,HYPRE_IJMatrix);
104 extern PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat,HYPRE_IJMatrix);
105 /*
106     Copies the data over (column indices, numerical values) to hypre matrix
107 */
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "MatHYPRE_IJMatrixCopy"
111 PetscErrorCode MatHYPRE_IJMatrixCopy(Mat A,HYPRE_IJMatrix ij)
112 {
113   PetscErrorCode    ierr;
114   PetscInt          i,rstart,rend,ncols;
115   const PetscScalar *values;
116   const PetscInt    *cols;
117   PetscBool         flg;
118 
119   PetscFunctionBegin;
120   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr);
121   if (flg) {
122     ierr = MatHYPRE_IJMatrixFastCopy_MPIAIJ(A,ij);CHKERRQ(ierr);
123     PetscFunctionReturn(0);
124   }
125   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&flg);CHKERRQ(ierr);
126   if (flg) {
127     ierr = MatHYPRE_IJMatrixFastCopy_SeqAIJ(A,ij);CHKERRQ(ierr);
128     PetscFunctionReturn(0);
129   }
130 
131   ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
132   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
133   ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);
134   for (i=rstart; i<rend; i++) {
135     ierr = MatGetRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr);
136     PetscStackCallStandard(HYPRE_IJMatrixSetValues,(ij,1,&ncols,&i,cols,values));
137     ierr = MatRestoreRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr);
138   }
139   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
140   ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
141   PetscFunctionReturn(0);
142 }
143 
144 /*
145     This copies the CSR format directly from the PETSc data structure to the hypre
146     data structure without calls to MatGetRow() or hypre's set values.
147 
148 */
149 #include <_hypre_IJ_mv.h>
150 #include <HYPRE_IJ_mv.h>
151 #include <../src/mat/impls/aij/mpi/mpiaij.h>
152 
153 #undef __FUNCT__
154 #define __FUNCT__ "MatHYPRE_IJMatrixFastCopy_SeqAIJ"
155 PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat A,HYPRE_IJMatrix ij)
156 {
157   PetscErrorCode ierr;
158   Mat_SeqAIJ     *pdiag = (Mat_SeqAIJ*)A->data;
159 
160   hypre_ParCSRMatrix    *par_matrix;
161   hypre_AuxParCSRMatrix *aux_matrix;
162   hypre_CSRMatrix       *hdiag;
163 
164   PetscFunctionBegin;
165   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
166   PetscValidType(A,1);
167   PetscValidPointer(ij,2);
168 
169   ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
170   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
171   par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij);
172   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
173   hdiag      = hypre_ParCSRMatrixDiag(par_matrix);
174 
175   /*
176        this is the Hack part where we monkey directly with the hypre datastructures
177   */
178   ierr = PetscMemcpy(hdiag->i,pdiag->i,(A->rmap->n + 1)*sizeof(PetscInt));
179   ierr = PetscMemcpy(hdiag->j,pdiag->j,pdiag->nz*sizeof(PetscInt));
180   ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));
181 
182   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
183   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
184   ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
185   PetscFunctionReturn(0);
186 }
187 
188 #undef __FUNCT__
189 #define __FUNCT__ "MatHYPRE_IJMatrixFastCopy_MPIAIJ"
190 PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat A,HYPRE_IJMatrix ij)
191 {
192   PetscErrorCode ierr;
193   Mat_MPIAIJ     *pA = (Mat_MPIAIJ*)A->data;
194   Mat_SeqAIJ     *pdiag,*poffd;
195   PetscInt       i,*garray = pA->garray,*jj,cstart,*pjj;
196 
197   hypre_ParCSRMatrix    *par_matrix;
198   hypre_AuxParCSRMatrix *aux_matrix;
199   hypre_CSRMatrix       *hdiag,*hoffd;
200 
201   PetscFunctionBegin;
202   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
203   PetscValidType(A,1);
204   PetscValidPointer(ij,2);
205   pdiag = (Mat_SeqAIJ*) pA->A->data;
206   poffd = (Mat_SeqAIJ*) pA->B->data;
207   /* cstart is only valid for square MPIAIJ layed out in the usual way */
208   ierr = MatGetOwnershipRange(A,&cstart,PETSC_NULL);CHKERRQ(ierr);
209 
210   ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
211   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
212   par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij);
213   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
214   hdiag      = hypre_ParCSRMatrixDiag(par_matrix);
215   hoffd      = hypre_ParCSRMatrixOffd(par_matrix);
216 
217   /*
218        this is the Hack part where we monkey directly with the hypre datastructures
219   */
220   ierr = PetscMemcpy(hdiag->i,pdiag->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
221   /* need to shift the diag column indices (hdiag->j) back to global numbering since hypre is expecting this */
222   jj  = hdiag->j;
223   pjj = pdiag->j;
224   for (i=0; i<pdiag->nz; i++) jj[i] = cstart + pjj[i];
225   ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));
226   ierr = PetscMemcpy(hoffd->i,poffd->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
227   /* need to move the offd column indices (hoffd->j) back to global numbering since hypre is expecting this
228      If we hacked a hypre a bit more we might be able to avoid this step */
229   jj  = hoffd->j;
230   pjj = poffd->j;
231   for (i=0; i<poffd->nz; i++) jj[i] = garray[pjj[i]];
232   ierr = PetscMemcpy(hoffd->data,poffd->a,poffd->nz*sizeof(PetscScalar));
233 
234   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
235   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
236   ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
237   PetscFunctionReturn(0);
238 }
239 
240 /*
241     Does NOT copy the data over, instead uses DIRECTLY the pointers from the PETSc MPIAIJ format
242 
243     This is UNFINISHED and does NOT work! The problem is that hypre puts the diagonal entry first
244     which will corrupt the PETSc data structure if we did this. Need a work around to this problem.
245 */
246 #include <_hypre_IJ_mv.h>
247 #include <HYPRE_IJ_mv.h>
248 
249 #undef __FUNCT__
250 #define __FUNCT__ "MatHYPRE_IJMatrixLink"
251 PetscErrorCode MatHYPRE_IJMatrixLink(Mat A,HYPRE_IJMatrix *ij)
252 {
253   PetscErrorCode        ierr;
254   PetscInt              rstart,rend,cstart,cend;
255   PetscBool             flg;
256   hypre_AuxParCSRMatrix *aux_matrix;
257 
258   PetscFunctionBegin;
259   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
260   PetscValidType(A,1);
261   PetscValidPointer(ij,2);
262   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr);
263   if (!flg) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"Can only use with PETSc MPIAIJ matrices");
264   ierr = MatSetUp(A);CHKERRQ(ierr);
265 
266   ierr   = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
267   rstart = A->rmap->rstart;
268   rend   = A->rmap->rend;
269   cstart = A->cmap->rstart;
270   cend   = A->cmap->rend;
271   PetscStackCallStandard(HYPRE_IJMatrixCreate,(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij));
272   PetscStackCallStandard(HYPRE_IJMatrixSetObjectType,(*ij,HYPRE_PARCSR));
273 
274   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(*ij));
275   PetscStackCall("hypre_IJMatrixTranslator",aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(*ij));
276 
277   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
278 
279   /* this is the Hack part where we monkey directly with the hypre datastructures */
280 
281   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(*ij));
282   ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr);
283   PetscFunctionReturn(0);
284 }
285 
286 /* -----------------------------------------------------------------------------------------------------------------*/
287 
288 /*MC
289    MATHYPRESTRUCT - MATHYPRESTRUCT = "hyprestruct" - A matrix type to be used for parallel sparse matrices
290           based on the hypre HYPRE_StructMatrix.
291 
292    Level: intermediate
293 
294    Notes: Unlike the more general support for blocks in hypre this allows only one block per process and requires the block
295           be defined by a DMDA.
296 
297           The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix()
298 
299 .seealso: MatCreate(), PCPFMG, MatSetupDM(), DMCreateMatrix()
300 M*/
301 
302 
303 #undef __FUNCT__
304 #define __FUNCT__ "MatSetValuesLocal_HYPREStruct_3d"
305 PetscErrorCode  MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
306 {
307   PetscErrorCode    ierr;
308   PetscInt          i,j,stencil,index[3],row,entries[7];
309   const PetscScalar *values = y;
310   Mat_HYPREStruct   *ex     = (Mat_HYPREStruct*) mat->data;
311 
312   PetscFunctionBegin;
313   for (i=0; i<nrow; i++) {
314     for (j=0; j<ncol; j++) {
315       stencil = icol[j] - irow[i];
316       if (!stencil) {
317         entries[j] = 3;
318       } else if (stencil == -1) {
319         entries[j] = 2;
320       } else if (stencil == 1) {
321         entries[j] = 4;
322       } else if (stencil == -ex->gnx) {
323         entries[j] = 1;
324       } else if (stencil == ex->gnx) {
325         entries[j] = 5;
326       } else if (stencil == -ex->gnxgny) {
327         entries[j] = 0;
328       } else if (stencil == ex->gnxgny) {
329         entries[j] = 6;
330       } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
331     }
332     row      = ex->gindices[irow[i]] - ex->rstart;
333     index[0] = ex->xs + (row % ex->nx);
334     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
335     index[2] = ex->zs + (row/(ex->nxny));
336     if (addv == ADD_VALUES) {
337       PetscStackCallStandard(HYPRE_StructMatrixAddToValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values));
338     } else {
339       PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values));
340     }
341     values += ncol;
342   }
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "MatZeroRowsLocal_HYPREStruct_3d"
348 PetscErrorCode  MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
349 {
350   PetscErrorCode  ierr;
351   PetscInt        i,index[3],row,entries[7] = {0,1,2,3,4,5,6};
352   PetscScalar     values[7];
353   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
354 
355   PetscFunctionBegin;
356   if (x && b) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"No support");
357   ierr      = PetscMemzero(values,7*sizeof(PetscScalar));CHKERRQ(ierr);
358   values[3] = d;
359   for (i=0; i<nrow; i++) {
360     row      = ex->gindices[irow[i]] - ex->rstart;
361     index[0] = ex->xs + (row % ex->nx);
362     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
363     index[2] = ex->zs + (row/(ex->nxny));
364     PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,index,7,entries,values));
365   }
366   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "MatZeroEntries_HYPREStruct_3d"
372 PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat)
373 {
374   PetscErrorCode  ierr;
375   PetscInt        indices[7] = {0,1,2,3,4,5,6};
376   Mat_HYPREStruct *ex        = (Mat_HYPREStruct*) mat->data;
377 
378   PetscFunctionBegin;
379   /* hypre has no public interface to do this */
380   PetscStackCallStandard(hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,indices,0,1));
381   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
382   PetscFunctionReturn(0);
383 }
384 
385 #undef __FUNCT__
386 #define __FUNCT__ "MatSetupDM_HYPREStruct"
387 PetscErrorCode  MatSetupDM_HYPREStruct(Mat mat,DM da)
388 {
389   PetscErrorCode   ierr;
390   Mat_HYPREStruct  *ex = (Mat_HYPREStruct*) mat->data;
391   PetscInt         dim,dof,sw[3],nx,ny,nz,ilower[3],iupper[3],ssize,i;
392   DMDABoundaryType px,py,pz;
393   DMDAStencilType  st;
394 
395   PetscFunctionBegin;
396   ex->da = da;
397   ierr   = PetscObjectReference((PetscObject)da);CHKERRQ(ierr);
398 
399   ierr       = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr);
400   ierr       = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
401   iupper[0] += ilower[0] - 1;
402   iupper[1] += ilower[1] - 1;
403   iupper[2] += ilower[2] - 1;
404 
405   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
406   ex->hbox.imin[0] = ilower[0];
407   ex->hbox.imin[1] = ilower[1];
408   ex->hbox.imin[2] = ilower[2];
409   ex->hbox.imax[0] = iupper[0];
410   ex->hbox.imax[1] = iupper[1];
411   ex->hbox.imax[2] = iupper[2];
412 
413   /* create the hypre grid object and set its information */
414   if (dof > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Currently only support for scalar problems");
415   if (px || py || pz) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()");
416   PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid));
417   PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,ilower,iupper));
418   PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid));
419 
420   sw[1] = sw[0];
421   sw[2] = sw[1];
422   PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,sw));
423 
424   /* create the hypre stencil object and set its information */
425   if (sw[0] > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for wider stencils");
426   if (st == DMDA_STENCIL_BOX) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for box stencils");
427   if (dim == 1) {
428     PetscInt offsets[3][1] = {{-1},{0},{1}};
429     ssize = 3;
430     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
431     for (i=0; i<ssize; i++) {
432       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
433     }
434   } else if (dim == 2) {
435     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
436     ssize = 5;
437     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
438     for (i=0; i<ssize; i++) {
439       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
440     }
441   } else if (dim == 3) {
442     PetscInt offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
443     ssize = 7;
444     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
445     for (i=0; i<ssize; i++) {
446       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
447     }
448   }
449 
450   /* create the HYPRE vector for rhs and solution */
451   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb));
452   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx));
453   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb));
454   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx));
455   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb));
456   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx));
457 
458   /* create the hypre matrix object and set its information */
459   PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat));
460   PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid));
461   PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil));
462   if (ex->needsinitialization) {
463     PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat));
464     ex->needsinitialization = PETSC_FALSE;
465   }
466 
467   /* set the global and local sizes of the matrix */
468   ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr);
469   ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
470   ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr);
471   ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr);
472   ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr);
473   ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr);
474 
475   if (dim == 3) {
476     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
477     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
478     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;
479 
480     ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr);
481   } else SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Only support for 3d DMDA currently");
482 
483   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
484   ierr        = MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);CHKERRQ(ierr);
485   ierr        = DMDAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);CHKERRQ(ierr);
486   ierr        = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr);
487   ex->gnxgny *= ex->gnx;
488   ierr        = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr);
489   ex->nxny    = ex->nx*ex->ny;
490   PetscFunctionReturn(0);
491 }
492 
493 #undef __FUNCT__
494 #define __FUNCT__ "MatMult_HYPREStruct"
495 PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
496 {
497   PetscErrorCode  ierr;
498   PetscScalar     *xx,*yy;
499   PetscInt        ilower[3],iupper[3];
500   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data);
501 
502   PetscFunctionBegin;
503   ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
504 
505   iupper[0] += ilower[0] - 1;
506   iupper[1] += ilower[1] - 1;
507   iupper[2] += ilower[2] - 1;
508 
509   /* copy x values over to hypre */
510   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
511   ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
512   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,ilower,iupper,xx));
513   ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
514   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
515   PetscStackCallStandard(HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx));
516 
517   /* copy solution values back to PETSc */
518   ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
519   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,ilower,iupper,yy));
520   ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
521   PetscFunctionReturn(0);
522 }
523 
524 #undef __FUNCT__
525 #define __FUNCT__ "MatAssemblyEnd_HYPREStruct"
526 PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode)
527 {
528   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
529   PetscErrorCode  ierr;
530 
531   PetscFunctionBegin;
532   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
533   /* PetscStackCallStandard(HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */
534   PetscFunctionReturn(0);
535 }
536 
537 #undef __FUNCT__
538 #define __FUNCT__ "MatZeroEntries_HYPREStruct"
539 PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat)
540 {
541   PetscFunctionBegin;
542   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
543   PetscFunctionReturn(0);
544 }
545 
546 
547 #undef __FUNCT__
548 #define __FUNCT__ "MatDestroy_HYPREStruct"
549 PetscErrorCode MatDestroy_HYPREStruct(Mat mat)
550 {
551   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
552   PetscErrorCode  ierr;
553 
554   PetscFunctionBegin;
555   PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat));
556   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx));
557   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb));
558   PetscFunctionReturn(0);
559 }
560 
561 
562 EXTERN_C_BEGIN
563 #undef __FUNCT__
564 #define __FUNCT__ "MatCreate_HYPREStruct"
565 PetscErrorCode  MatCreate_HYPREStruct(Mat B)
566 {
567   Mat_HYPREStruct *ex;
568   PetscErrorCode  ierr;
569 
570   PetscFunctionBegin;
571   ierr         = PetscNewLog(B,Mat_HYPREStruct,&ex);CHKERRQ(ierr);
572   B->data      = (void*)ex;
573   B->rmap->bs  = 1;
574   B->assembled = PETSC_FALSE;
575 
576   B->insertmode = NOT_SET_VALUES;
577 
578   B->ops->assemblyend = MatAssemblyEnd_HYPREStruct;
579   B->ops->mult        = MatMult_HYPREStruct;
580   B->ops->zeroentries = MatZeroEntries_HYPREStruct;
581   B->ops->destroy     = MatDestroy_HYPREStruct;
582 
583   ex->needsinitialization = PETSC_TRUE;
584 
585   ierr = MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));CHKERRQ(ierr);
586   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetupDM_C","MatSetupDM_HYPREStruct",MatSetupDM_HYPREStruct);CHKERRQ(ierr);
587   ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr);
588   PetscFunctionReturn(0);
589 }
590 EXTERN_C_END
591 
592 
593 /*MC
594    MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices
595           based on the hypre HYPRE_SStructMatrix.
596 
597 
598    Level: intermediate
599 
600    Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured
601           grid objects, we will restrict the semi-struct objects to consist of only structured-grid components.
602 
603           Unlike the more general support for parts and blocks in hypre this allows only one part, and one block per process and requires the block
604           be defined by a DMDA.
605 
606           The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix()
607 
608 M*/
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "MatSetValuesLocal_HYPRESStruct_3d"
612 PetscErrorCode  MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
613 {
614   PetscErrorCode    ierr;
615   PetscInt          i,j,stencil,index[3];
616   const PetscScalar *values = y;
617   Mat_HYPRESStruct  *ex     = (Mat_HYPRESStruct*) mat->data;
618 
619   PetscInt part = 0;          /* Petsc sstruct interface only allows 1 part */
620   PetscInt ordering;
621   PetscInt grid_rank, to_grid_rank;
622   PetscInt var_type, to_var_type;
623   PetscInt to_var_entry = 0;
624 
625   PetscInt nvars= ex->nvars;
626   PetscInt row,*entries;
627 
628   PetscFunctionBegin;
629   ierr    = PetscMalloc(7*nvars*sizeof(PetscInt),&entries);CHKERRQ(ierr);
630   ordering= ex->dofs_order;  /* ordering= 0   nodal ordering
631                                           1   variable ordering */
632   /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ...  */
633 
634   if (!ordering) {
635     for (i=0; i<nrow; i++) {
636       grid_rank= irow[i]/nvars;
637       var_type = (irow[i] % nvars);
638 
639       for (j=0; j<ncol; j++) {
640         to_grid_rank= icol[j]/nvars;
641         to_var_type = (icol[j] % nvars);
642 
643         to_var_entry= to_var_entry*7;
644         entries[j]  = to_var_entry;
645 
646         stencil = to_grid_rank-grid_rank;
647         if (!stencil) {
648           entries[j] += 3;
649         } else if (stencil == -1) {
650           entries[j] += 2;
651         } else if (stencil == 1) {
652           entries[j] += 4;
653         } else if (stencil == -ex->gnx) {
654           entries[j] += 1;
655         } else if (stencil == ex->gnx) {
656           entries[j] += 5;
657         } else if (stencil == -ex->gnxgny) {
658           entries[j] += 0;
659         } else if (stencil == ex->gnxgny) {
660           entries[j] += 6;
661         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
662       }
663 
664       row      = ex->gindices[grid_rank] - ex->rstart;
665       index[0] = ex->xs + (row % ex->nx);
666       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
667       index[2] = ex->zs + (row/(ex->nxny));
668 
669       if (addv == ADD_VALUES) {
670         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
671       } else {
672         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
673       }
674       values += ncol;
675     }
676   } else {
677     for (i=0; i<nrow; i++) {
678       var_type = irow[i]/(ex->gnxgnygnz);
679       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);
680 
681       for (j=0; j<ncol; j++) {
682         to_var_type = icol[j]/(ex->gnxgnygnz);
683         to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz);
684 
685         to_var_entry= to_var_entry*7;
686         entries[j]  = to_var_entry;
687 
688         stencil = to_grid_rank-grid_rank;
689         if (!stencil) {
690           entries[j] += 3;
691         } else if (stencil == -1) {
692           entries[j] += 2;
693         } else if (stencil == 1) {
694           entries[j] += 4;
695         } else if (stencil == -ex->gnx) {
696           entries[j] += 1;
697         } else if (stencil == ex->gnx) {
698           entries[j] += 5;
699         } else if (stencil == -ex->gnxgny) {
700           entries[j] += 0;
701         } else if (stencil == ex->gnxgny) {
702           entries[j] += 6;
703         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
704       }
705 
706       row      = ex->gindices[grid_rank] - ex->rstart;
707       index[0] = ex->xs + (row % ex->nx);
708       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
709       index[2] = ex->zs + (row/(ex->nxny));
710 
711       if (addv == ADD_VALUES) {
712         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
713       } else {
714         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
715       }
716       values += ncol;
717     }
718   }
719   ierr = PetscFree(entries);CHKERRQ(ierr);
720   PetscFunctionReturn(0);
721 }
722 
723 #undef __FUNCT__
724 #define __FUNCT__ "MatZeroRowsLocal_HYPRESStruct_3d"
725 PetscErrorCode  MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
726 {
727   PetscErrorCode   ierr;
728   PetscInt         i,index[3];
729   PetscScalar      **values;
730   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
731 
732   PetscInt part     = 0;      /* Petsc sstruct interface only allows 1 part */
733   PetscInt ordering = ex->dofs_order;
734   PetscInt grid_rank;
735   PetscInt var_type;
736   PetscInt nvars= ex->nvars;
737   PetscInt row,*entries;
738 
739   PetscFunctionBegin;
740   if (x && b) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"No support");
741   ierr = PetscMalloc(7*nvars*sizeof(PetscInt),&entries);CHKERRQ(ierr);
742 
743   ierr = PetscMalloc(nvars*sizeof(PetscScalar*),&values);CHKERRQ(ierr);
744   ierr = PetscMalloc(7*nvars*nvars*sizeof(PetscScalar),&values[0]);CHKERRQ(ierr);
745   for (i=1; i<nvars; i++) {
746     values[i] = values[i-1] + nvars*7;
747   }
748 
749   for (i=0; i< nvars; i++) {
750     ierr           = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr);
751     *(values[i]+3) = d;
752   }
753 
754   for (i= 0; i< nvars*7; i++) entries[i] = i;
755 
756   if (!ordering) {
757     for (i=0; i<nrow; i++) {
758       grid_rank = irow[i] / nvars;
759       var_type  =(irow[i] % nvars);
760 
761       row      = ex->gindices[grid_rank] - ex->rstart;
762       index[0] = ex->xs + (row % ex->nx);
763       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
764       index[2] = ex->zs + (row/(ex->nxny));
765       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]));
766     }
767   } else {
768     for (i=0; i<nrow; i++) {
769       var_type = irow[i]/(ex->gnxgnygnz);
770       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);
771 
772       row      = ex->gindices[grid_rank] - ex->rstart;
773       index[0] = ex->xs + (row % ex->nx);
774       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
775       index[2] = ex->zs + (row/(ex->nxny));
776       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]));
777     }
778   }
779   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
780   ierr = PetscFree(values[0]);CHKERRQ(ierr);
781   ierr = PetscFree(values);CHKERRQ(ierr);
782   ierr = PetscFree(entries);CHKERRQ(ierr);
783   PetscFunctionReturn(0);
784 }
785 
786 #undef __FUNCT__
787 #define __FUNCT__ "MatZeroEntries_HYPRESStruct_3d"
788 PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat)
789 {
790   PetscErrorCode   ierr;
791   Mat_HYPRESStruct *ex  = (Mat_HYPRESStruct*) mat->data;
792   PetscInt         nvars= ex->nvars;
793   PetscInt         size;
794   PetscInt         part= 0;   /* only one part */
795 
796   PetscFunctionBegin;
797   size = ((ex->hbox.imax[0])-(ex->hbox.imin[0])+1)*((ex->hbox.imax[1])-(ex->hbox.imin[1])+1)*((ex->hbox.imax[2])-(ex->hbox.imin[2])+1);
798   {
799     PetscInt    i,*entries,iupper[3],ilower[3];
800     PetscScalar *values;
801 
802 
803     for (i= 0; i< 3; i++) {
804       ilower[i]= ex->hbox.imin[i];
805       iupper[i]= ex->hbox.imax[i];
806     }
807 
808     ierr = PetscMalloc2(nvars*7,PetscInt,&entries,nvars*7*size,PetscScalar,&values);CHKERRQ(ierr);
809     for (i= 0; i< nvars*7; i++) entries[i]= i;
810     ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr);
811 
812     for (i= 0; i< nvars; i++) {
813       PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values));
814     }
815     ierr = PetscFree2(entries,values);CHKERRQ(ierr);
816   }
817   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
818   PetscFunctionReturn(0);
819 }
820 
821 
822 #undef __FUNCT__
823 #define __FUNCT__ "MatSetupDM_HYPRESStruct"
824 PetscErrorCode  MatSetupDM_HYPRESStruct(Mat mat,DM da)
825 {
826   PetscErrorCode   ierr;
827   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
828   PetscInt         dim,dof,sw[3],nx,ny,nz;
829   PetscInt         ilower[3],iupper[3],ssize,i;
830   DMDABoundaryType px,py,pz;
831   DMDAStencilType  st;
832   PetscInt         nparts= 1;  /* assuming only one part */
833   PetscInt         part  = 0;
834 
835   PetscFunctionBegin;
836   ex->da = da;
837   ierr   = PetscObjectReference((PetscObject)da);CHKERRQ(ierr);
838 
839   ierr       = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr);
840   ierr       = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
841   iupper[0] += ilower[0] - 1;
842   iupper[1] += ilower[1] - 1;
843   iupper[2] += ilower[2] - 1;
844   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
845   ex->hbox.imin[0] = ilower[0];
846   ex->hbox.imin[1] = ilower[1];
847   ex->hbox.imin[2] = ilower[2];
848   ex->hbox.imax[0] = iupper[0];
849   ex->hbox.imax[1] = iupper[1];
850   ex->hbox.imax[2] = iupper[2];
851 
852   ex->dofs_order = 0;
853 
854   /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */
855   ex->nvars= dof;
856 
857   /* create the hypre grid object and set its information */
858   if (px || py || pz) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()");
859   PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid));
860 
861   PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax));
862 
863   {
864     HYPRE_SStructVariable *vartypes;
865     ierr = PetscMalloc(ex->nvars*sizeof(HYPRE_SStructVariable),&vartypes);CHKERRQ(ierr);
866     for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
867     PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes));
868     ierr = PetscFree(vartypes);CHKERRQ(ierr);
869   }
870   PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid));
871 
872   sw[1] = sw[0];
873   sw[2] = sw[1];
874   /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */
875 
876   /* create the hypre stencil object and set its information */
877   if (sw[0] > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for wider stencils");
878   if (st == DMDA_STENCIL_BOX) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for box stencils");
879 
880   if (dim == 1) {
881     PetscInt offsets[3][1] = {{-1},{0},{1}};
882     PetscInt j, cnt;
883 
884     ssize = 3*(ex->nvars);
885     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
886     cnt= 0;
887     for (i = 0; i < (ex->nvars); i++) {
888       for (j = 0; j < 3; j++) {
889         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
890         cnt++;
891       }
892     }
893   } else if (dim == 2) {
894     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
895     PetscInt j, cnt;
896 
897     ssize = 5*(ex->nvars);
898     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
899     cnt= 0;
900     for (i= 0; i< (ex->nvars); i++) {
901       for (j= 0; j< 5; j++) {
902         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
903         cnt++;
904       }
905     }
906   } else if (dim == 3) {
907     PetscInt offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
908     PetscInt j, cnt;
909 
910     ssize = 7*(ex->nvars);
911     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
912     cnt= 0;
913     for (i= 0; i< (ex->nvars); i++) {
914       for (j= 0; j< 7; j++) {
915         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
916         cnt++;
917       }
918     }
919   }
920 
921   /* create the HYPRE graph */
922   PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph)));
923 
924   /* set the stencil graph. Note that each variable has the same graph. This means that each
925      variable couples to all the other variable and with the same stencil pattern. */
926   for (i= 0; i< (ex->nvars); i++) {
927     PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil));
928   }
929   PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph));
930 
931   /* create the HYPRE sstruct vectors for rhs and solution */
932   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b));
933   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x));
934   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b));
935   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x));
936   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b));
937   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x));
938 
939   /* create the hypre matrix object and set its information */
940   PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat));
941   PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid));
942   PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil));
943   if (ex->needsinitialization) {
944     PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat));
945     ex->needsinitialization = PETSC_FALSE;
946   }
947 
948   /* set the global and local sizes of the matrix */
949   ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr);
950   ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
951   ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr);
952   ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr);
953   ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr);
954   ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr);
955 
956   if (dim == 3) {
957     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
958     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
959     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;
960 
961     ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr);
962   } else SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Only support for 3d DMDA currently");
963 
964   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
965   ierr = MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);CHKERRQ(ierr);
966   ierr = DMDAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);CHKERRQ(ierr);
967   ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);CHKERRQ(ierr);
968 
969   ex->gnxgny    *= ex->gnx;
970   ex->gnxgnygnz *= ex->gnxgny;
971 
972   ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);CHKERRQ(ierr);
973 
974   ex->nxny   = ex->nx*ex->ny;
975   ex->nxnynz = ex->nz*ex->nxny;
976   PetscFunctionReturn(0);
977 }
978 
979 #undef __FUNCT__
980 #define __FUNCT__ "MatMult_HYPRESStruct"
981 PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y)
982 {
983   PetscErrorCode   ierr;
984   PetscScalar      *xx,*yy;
985   PetscInt         ilower[3],iupper[3];
986   Mat_HYPRESStruct *mx     = (Mat_HYPRESStruct*)(A->data);
987   PetscInt         ordering= mx->dofs_order;
988   PetscInt         nvars   = mx->nvars;
989   PetscInt         part    = 0;
990   PetscInt         size;
991   PetscInt         i;
992 
993   PetscFunctionBegin;
994   ierr       = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
995   iupper[0] += ilower[0] - 1;
996   iupper[1] += ilower[1] - 1;
997   iupper[2] += ilower[2] - 1;
998 
999   size= 1;
1000   for (i = 0; i < 3; i++) size *= (iupper[i]-ilower[i]+1);
1001 
1002   /* copy x values over to hypre for variable ordering */
1003   if (ordering) {
1004     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1005     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1006     for (i= 0; i< nvars; i++) {
1007       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,xx+(size*i)));
1008     }
1009     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1010     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1011     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));
1012 
1013     /* copy solution values back to PETSc */
1014     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1015     for (i= 0; i< nvars; i++) {
1016       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,yy+(size*i)));
1017     }
1018     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1019   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
1020     PetscScalar *z;
1021     PetscInt    j, k;
1022 
1023     ierr = PetscMalloc(nvars*size*sizeof(PetscScalar),&z);CHKERRQ(ierr);
1024     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1025     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1026 
1027     /* transform nodal to hypre's variable ordering for sys_pfmg */
1028     for (i= 0; i< size; i++) {
1029       k= i*nvars;
1030       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
1031     }
1032     for (i= 0; i< nvars; i++) {
1033       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,z+(size*i)));
1034     }
1035     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1036     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1037     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));
1038 
1039     /* copy solution values back to PETSc */
1040     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1041     for (i= 0; i< nvars; i++) {
1042       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,z+(size*i)));
1043     }
1044     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
1045     for (i= 0; i< size; i++) {
1046       k= i*nvars;
1047       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
1048     }
1049     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1050     ierr = PetscFree(z);CHKERRQ(ierr);
1051   }
1052   PetscFunctionReturn(0);
1053 }
1054 
1055 #undef __FUNCT__
1056 #define __FUNCT__ "MatAssemblyEnd_HYPRESStruct"
1057 PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode)
1058 {
1059   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
1060   PetscErrorCode   ierr;
1061 
1062   PetscFunctionBegin;
1063   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 #undef __FUNCT__
1068 #define __FUNCT__ "MatZeroEntries_HYPRESStruct"
1069 PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat)
1070 {
1071   PetscFunctionBegin;
1072   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
1073   PetscFunctionReturn(0);
1074 }
1075 
1076 
1077 #undef __FUNCT__
1078 #define __FUNCT__ "MatDestroy_HYPRESStruct"
1079 PetscErrorCode MatDestroy_HYPRESStruct(Mat mat)
1080 {
1081   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
1082   PetscErrorCode   ierr;
1083 
1084   PetscFunctionBegin;
1085   PetscStackCallStandard(HYPRE_SStructGraphDestroy,(ex->ss_graph));
1086   PetscStackCallStandard(HYPRE_SStructMatrixDestroy,(ex->ss_mat));
1087   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_x));
1088   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_b));
1089   PetscFunctionReturn(0);
1090 }
1091 
1092 EXTERN_C_BEGIN
1093 #undef __FUNCT__
1094 #define __FUNCT__ "MatCreate_HYPRESStruct"
1095 PetscErrorCode  MatCreate_HYPRESStruct(Mat B)
1096 {
1097   Mat_HYPRESStruct *ex;
1098   PetscErrorCode   ierr;
1099 
1100   PetscFunctionBegin;
1101   ierr         = PetscNewLog(B,Mat_HYPRESStruct,&ex);CHKERRQ(ierr);
1102   B->data      = (void*)ex;
1103   B->rmap->bs  = 1;
1104   B->assembled = PETSC_FALSE;
1105 
1106   B->insertmode = NOT_SET_VALUES;
1107 
1108   B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct;
1109   B->ops->mult        = MatMult_HYPRESStruct;
1110   B->ops->zeroentries = MatZeroEntries_HYPRESStruct;
1111   B->ops->destroy     = MatDestroy_HYPRESStruct;
1112 
1113   ex->needsinitialization = PETSC_TRUE;
1114 
1115   ierr = MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));CHKERRQ(ierr);
1116   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetupDM_C","MatSetupDM_HYPRESStruct",MatSetupDM_HYPRESStruct);CHKERRQ(ierr);
1117   ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr);
1118   PetscFunctionReturn(0);
1119 }
1120 EXTERN_C_END
1121 
1122 
1123 
1124