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