xref: /petsc/src/dm/impls/da/hypre/mhyp.c (revision 4cefc2ff75e4fd40cdd0827272dcde5d684e9831)
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=NULL,*nnz_o=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,NULL,&done_d);CHKERRQ(ierr);
23     if (done_d) {
24       ierr = PetscMalloc1(n_d,&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,NULL,&ia_d,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,NULL,&done_o);CHKERRQ(ierr);
33     if (done_o) {
34       ierr = PetscMalloc1(n_o,&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,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 = PetscMalloc1(n_d,&nnz_o);CHKERRQ(ierr);
44       for (i=0; i<n_d; i++) {
45         nnz_o[i] = 0;
46       }
47     }
48     PetscStackCallStandard(HYPRE_IJMatrixSetDiagOffdSizes,(ij,(HYPRE_Int *)nnz_d,(HYPRE_Int *)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,(PetscObjectComm((PetscObject)A),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,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,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,(HYPRE_Int *)&ncols,(HYPRE_Int *)&i,(HYPRE_Int *)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,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  = (PetscInt*)hdiag->j;
223   pjj = (PetscInt*)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  = (PetscInt*) hoffd->j;
230   pjj = (PetscInt*) 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(PetscObjectComm((PetscObject)A),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,(PetscObjectComm((PetscObject)A),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,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
338     } else {
339       PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)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(PetscObjectComm((PetscObject)mat),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,(HYPRE_Int *)index,7,(HYPRE_Int *)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,(HYPRE_Int *)indices,0,1));
381   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
382   PetscFunctionReturn(0);
383 }
384 
385 #undef __FUNCT__
386 #define __FUNCT__ "MatSetupDM_HYPREStruct"
387 static 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   DMBoundaryType         px,py,pz;
393   DMDAStencilType        st;
394   ISLocalToGlobalMapping ltog;
395 
396   PetscFunctionBegin;
397   ex->da = da;
398   ierr   = PetscObjectReference((PetscObject)da);CHKERRQ(ierr);
399 
400   ierr       = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr);
401   ierr       = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
402   iupper[0] += ilower[0] - 1;
403   iupper[1] += ilower[1] - 1;
404   iupper[2] += ilower[2] - 1;
405 
406   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
407   ex->hbox.imin[0] = ilower[0];
408   ex->hbox.imin[1] = ilower[1];
409   ex->hbox.imin[2] = ilower[2];
410   ex->hbox.imax[0] = iupper[0];
411   ex->hbox.imax[1] = iupper[1];
412   ex->hbox.imax[2] = iupper[2];
413 
414   /* create the hypre grid object and set its information */
415   if (dof > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems");
416   if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()");
417   PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid));
418   PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper));
419   PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid));
420 
421   sw[1] = sw[0];
422   sw[2] = sw[1];
423   PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,(HYPRE_Int *)sw));
424 
425   /* create the hypre stencil object and set its information */
426   if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils");
427   if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils");
428   if (dim == 1) {
429     PetscInt offsets[3][1] = {{-1},{0},{1}};
430     ssize = 3;
431     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
432     for (i=0; i<ssize; i++) {
433       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
434     }
435   } else if (dim == 2) {
436     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
437     ssize = 5;
438     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
439     for (i=0; i<ssize; i++) {
440       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
441     }
442   } else if (dim == 3) {
443     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}};
444     ssize = 7;
445     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
446     for (i=0; i<ssize; i++) {
447       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
448     }
449   }
450 
451   /* create the HYPRE vector for rhs and solution */
452   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb));
453   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx));
454   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb));
455   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx));
456   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb));
457   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx));
458 
459   /* create the hypre matrix object and set its information */
460   PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat));
461   PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid));
462   PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil));
463   if (ex->needsinitialization) {
464     PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat));
465     ex->needsinitialization = PETSC_FALSE;
466   }
467 
468   /* set the global and local sizes of the matrix */
469   ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr);
470   ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
471   ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr);
472   ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr);
473   ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr);
474   ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr);
475 
476   if (dim == 3) {
477     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
478     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
479     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;
480 
481     ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr);
482   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");
483 
484   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
485   ierr        = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr);
486   ierr        = DMGetLocalToGlobalMapping(ex->da,&ltog);CHKERRQ(ierr);
487   ierr        = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr);
488   ierr        = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr);
489   ex->gnxgny *= ex->gnx;
490   ierr        = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr);
491   ex->nxny    = ex->nx*ex->ny;
492   PetscFunctionReturn(0);
493 }
494 
495 #undef __FUNCT__
496 #define __FUNCT__ "MatMult_HYPREStruct"
497 PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
498 {
499   PetscErrorCode  ierr;
500   PetscScalar     *xx,*yy;
501   PetscInt        ilower[3],iupper[3];
502   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data);
503 
504   PetscFunctionBegin;
505   ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
506 
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   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
513   ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
514   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,xx));
515   ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
516   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
517   PetscStackCallStandard(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   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,(HYPRE_Int *)ilower,(HYPRE_Int *)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   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
535   /* PetscStackCallStandard(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   PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat));
558   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx));
559   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb));
560   PetscFunctionReturn(0);
561 }
562 
563 
564 #undef __FUNCT__
565 #define __FUNCT__ "MatCreate_HYPREStruct"
566 PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B)
567 {
568   Mat_HYPREStruct *ex;
569   PetscErrorCode  ierr;
570 
571   PetscFunctionBegin;
572   ierr         = PetscNewLog(B,&ex);CHKERRQ(ierr);
573   B->data      = (void*)ex;
574   B->rmap->bs  = 1;
575   B->assembled = PETSC_FALSE;
576 
577   B->insertmode = NOT_SET_VALUES;
578 
579   B->ops->assemblyend = MatAssemblyEnd_HYPREStruct;
580   B->ops->mult        = MatMult_HYPREStruct;
581   B->ops->zeroentries = MatZeroEntries_HYPREStruct;
582   B->ops->destroy     = MatDestroy_HYPREStruct;
583 
584   ex->needsinitialization = PETSC_TRUE;
585 
586   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr);
587   ierr = PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPREStruct);CHKERRQ(ierr);
588   ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr);
589   PetscFunctionReturn(0);
590 }
591 
592 /*MC
593    MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices
594           based on the hypre HYPRE_SStructMatrix.
595 
596 
597    Level: intermediate
598 
599    Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured
600           grid objects, we will restrict the semi-struct objects to consist of only structured-grid components.
601 
602           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
603           be defined by a DMDA.
604 
605           The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix()
606 
607 M*/
608 
609 #undef __FUNCT__
610 #define __FUNCT__ "MatSetValuesLocal_HYPRESStruct_3d"
611 PetscErrorCode  MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
612 {
613   PetscErrorCode    ierr;
614   PetscInt          i,j,stencil,index[3];
615   const PetscScalar *values = y;
616   Mat_HYPRESStruct  *ex     = (Mat_HYPRESStruct*) mat->data;
617 
618   PetscInt part = 0;          /* Petsc sstruct interface only allows 1 part */
619   PetscInt ordering;
620   PetscInt grid_rank, to_grid_rank;
621   PetscInt var_type, to_var_type;
622   PetscInt to_var_entry = 0;
623 
624   PetscInt nvars= ex->nvars;
625   PetscInt row,*entries;
626 
627   PetscFunctionBegin;
628   ierr    = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr);
629   ordering= ex->dofs_order;  /* ordering= 0   nodal ordering
630                                           1   variable ordering */
631   /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ...  */
632 
633   if (!ordering) {
634     for (i=0; i<nrow; i++) {
635       grid_rank= irow[i]/nvars;
636       var_type = (irow[i] % nvars);
637 
638       for (j=0; j<ncol; j++) {
639         to_grid_rank= icol[j]/nvars;
640         to_var_type = (icol[j] % nvars);
641 
642         to_var_entry= to_var_entry*7;
643         entries[j]  = to_var_entry;
644 
645         stencil = to_grid_rank-grid_rank;
646         if (!stencil) {
647           entries[j] += 3;
648         } else if (stencil == -1) {
649           entries[j] += 2;
650         } else if (stencil == 1) {
651           entries[j] += 4;
652         } else if (stencil == -ex->gnx) {
653           entries[j] += 1;
654         } else if (stencil == ex->gnx) {
655           entries[j] += 5;
656         } else if (stencil == -ex->gnxgny) {
657           entries[j] += 0;
658         } else if (stencil == ex->gnxgny) {
659           entries[j] += 6;
660         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
661       }
662 
663       row      = ex->gindices[grid_rank] - ex->rstart;
664       index[0] = ex->xs + (row % ex->nx);
665       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
666       index[2] = ex->zs + (row/(ex->nxny));
667 
668       if (addv == ADD_VALUES) {
669         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
670       } else {
671         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
672       }
673       values += ncol;
674     }
675   } else {
676     for (i=0; i<nrow; i++) {
677       var_type = irow[i]/(ex->gnxgnygnz);
678       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);
679 
680       for (j=0; j<ncol; j++) {
681         to_var_type = icol[j]/(ex->gnxgnygnz);
682         to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz);
683 
684         to_var_entry= to_var_entry*7;
685         entries[j]  = to_var_entry;
686 
687         stencil = to_grid_rank-grid_rank;
688         if (!stencil) {
689           entries[j] += 3;
690         } else if (stencil == -1) {
691           entries[j] += 2;
692         } else if (stencil == 1) {
693           entries[j] += 4;
694         } else if (stencil == -ex->gnx) {
695           entries[j] += 1;
696         } else if (stencil == ex->gnx) {
697           entries[j] += 5;
698         } else if (stencil == -ex->gnxgny) {
699           entries[j] += 0;
700         } else if (stencil == ex->gnxgny) {
701           entries[j] += 6;
702         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
703       }
704 
705       row      = ex->gindices[grid_rank] - ex->rstart;
706       index[0] = ex->xs + (row % ex->nx);
707       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
708       index[2] = ex->zs + (row/(ex->nxny));
709 
710       if (addv == ADD_VALUES) {
711         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
712       } else {
713         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
714       }
715       values += ncol;
716     }
717   }
718   ierr = PetscFree(entries);CHKERRQ(ierr);
719   PetscFunctionReturn(0);
720 }
721 
722 #undef __FUNCT__
723 #define __FUNCT__ "MatZeroRowsLocal_HYPRESStruct_3d"
724 PetscErrorCode  MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
725 {
726   PetscErrorCode   ierr;
727   PetscInt         i,index[3];
728   PetscScalar      **values;
729   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
730 
731   PetscInt part     = 0;      /* Petsc sstruct interface only allows 1 part */
732   PetscInt ordering = ex->dofs_order;
733   PetscInt grid_rank;
734   PetscInt var_type;
735   PetscInt nvars= ex->nvars;
736   PetscInt row,*entries;
737 
738   PetscFunctionBegin;
739   if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support");
740   ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr);
741 
742   ierr = PetscMalloc1(nvars,&values);CHKERRQ(ierr);
743   ierr = PetscMalloc1(7*nvars*nvars,&values[0]);CHKERRQ(ierr);
744   for (i=1; i<nvars; i++) {
745     values[i] = values[i-1] + nvars*7;
746   }
747 
748   for (i=0; i< nvars; i++) {
749     ierr           = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr);
750     *(values[i]+3) = d;
751   }
752 
753   for (i= 0; i< nvars*7; i++) entries[i] = i;
754 
755   if (!ordering) {
756     for (i=0; i<nrow; i++) {
757       grid_rank = irow[i] / nvars;
758       var_type  =(irow[i] % nvars);
759 
760       row      = ex->gindices[grid_rank] - ex->rstart;
761       index[0] = ex->xs + (row % ex->nx);
762       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
763       index[2] = ex->zs + (row/(ex->nxny));
764       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type]));
765     }
766   } else {
767     for (i=0; i<nrow; i++) {
768       var_type = irow[i]/(ex->gnxgnygnz);
769       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);
770 
771       row      = ex->gindices[grid_rank] - ex->rstart;
772       index[0] = ex->xs + (row % ex->nx);
773       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
774       index[2] = ex->zs + (row/(ex->nxny));
775       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type]));
776     }
777   }
778   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
779   ierr = PetscFree(values[0]);CHKERRQ(ierr);
780   ierr = PetscFree(values);CHKERRQ(ierr);
781   ierr = PetscFree(entries);CHKERRQ(ierr);
782   PetscFunctionReturn(0);
783 }
784 
785 #undef __FUNCT__
786 #define __FUNCT__ "MatZeroEntries_HYPRESStruct_3d"
787 PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat)
788 {
789   PetscErrorCode   ierr;
790   Mat_HYPRESStruct *ex  = (Mat_HYPRESStruct*) mat->data;
791   PetscInt         nvars= ex->nvars;
792   PetscInt         size;
793   PetscInt         part= 0;   /* only one part */
794 
795   PetscFunctionBegin;
796   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);
797   {
798     PetscInt    i,*entries,iupper[3],ilower[3];
799     PetscScalar *values;
800 
801 
802     for (i= 0; i< 3; i++) {
803       ilower[i]= ex->hbox.imin[i];
804       iupper[i]= ex->hbox.imax[i];
805     }
806 
807     ierr = PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);CHKERRQ(ierr);
808     for (i= 0; i< nvars*7; i++) entries[i]= i;
809     ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr);
810 
811     for (i= 0; i< nvars; i++) {
812       PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,nvars*7,(HYPRE_Int *)entries,values));
813     }
814     ierr = PetscFree2(entries,values);CHKERRQ(ierr);
815   }
816   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
817   PetscFunctionReturn(0);
818 }
819 
820 
821 #undef __FUNCT__
822 #define __FUNCT__ "MatSetupDM_HYPRESStruct"
823 static PetscErrorCode  MatSetupDM_HYPRESStruct(Mat mat,DM da)
824 {
825   PetscErrorCode         ierr;
826   Mat_HYPRESStruct       *ex = (Mat_HYPRESStruct*) mat->data;
827   PetscInt               dim,dof,sw[3],nx,ny,nz;
828   PetscInt               ilower[3],iupper[3],ssize,i;
829   DMBoundaryType         px,py,pz;
830   DMDAStencilType        st;
831   PetscInt               nparts= 1;  /* assuming only one part */
832   PetscInt               part  = 0;
833   ISLocalToGlobalMapping ltog;
834   PetscFunctionBegin;
835   ex->da = da;
836   ierr   = PetscObjectReference((PetscObject)da);CHKERRQ(ierr);
837 
838   ierr       = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr);
839   ierr       = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
840   iupper[0] += ilower[0] - 1;
841   iupper[1] += ilower[1] - 1;
842   iupper[2] += ilower[2] - 1;
843   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
844   ex->hbox.imin[0] = ilower[0];
845   ex->hbox.imin[1] = ilower[1];
846   ex->hbox.imin[2] = ilower[2];
847   ex->hbox.imax[0] = iupper[0];
848   ex->hbox.imax[1] = iupper[1];
849   ex->hbox.imax[2] = iupper[2];
850 
851   ex->dofs_order = 0;
852 
853   /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */
854   ex->nvars= dof;
855 
856   /* create the hypre grid object and set its information */
857   if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()");
858   PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid));
859 
860   PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax));
861 
862   {
863     HYPRE_SStructVariable *vartypes;
864     ierr = PetscMalloc1(ex->nvars,&vartypes);CHKERRQ(ierr);
865     for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
866     PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes));
867     ierr = PetscFree(vartypes);CHKERRQ(ierr);
868   }
869   PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid));
870 
871   sw[1] = sw[0];
872   sw[2] = sw[1];
873   /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */
874 
875   /* create the hypre stencil object and set its information */
876   if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils");
877   if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils");
878 
879   if (dim == 1) {
880     PetscInt offsets[3][1] = {{-1},{0},{1}};
881     PetscInt j, cnt;
882 
883     ssize = 3*(ex->nvars);
884     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
885     cnt= 0;
886     for (i = 0; i < (ex->nvars); i++) {
887       for (j = 0; j < 3; j++) {
888         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
889         cnt++;
890       }
891     }
892   } else if (dim == 2) {
893     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
894     PetscInt j, cnt;
895 
896     ssize = 5*(ex->nvars);
897     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
898     cnt= 0;
899     for (i= 0; i< (ex->nvars); i++) {
900       for (j= 0; j< 5; j++) {
901         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
902         cnt++;
903       }
904     }
905   } else if (dim == 3) {
906     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}};
907     PetscInt j, cnt;
908 
909     ssize = 7*(ex->nvars);
910     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
911     cnt= 0;
912     for (i= 0; i< (ex->nvars); i++) {
913       for (j= 0; j< 7; j++) {
914         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
915         cnt++;
916       }
917     }
918   }
919 
920   /* create the HYPRE graph */
921   PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph)));
922 
923   /* set the stencil graph. Note that each variable has the same graph. This means that each
924      variable couples to all the other variable and with the same stencil pattern. */
925   for (i= 0; i< (ex->nvars); i++) {
926     PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil));
927   }
928   PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph));
929 
930   /* create the HYPRE sstruct vectors for rhs and solution */
931   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b));
932   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x));
933   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b));
934   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x));
935   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b));
936   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x));
937 
938   /* create the hypre matrix object and set its information */
939   PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat));
940   PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid));
941   PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil));
942   if (ex->needsinitialization) {
943     PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat));
944     ex->needsinitialization = PETSC_FALSE;
945   }
946 
947   /* set the global and local sizes of the matrix */
948   ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr);
949   ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
950   ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr);
951   ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr);
952   ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr);
953   ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr);
954 
955   if (dim == 3) {
956     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
957     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
958     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;
959 
960     ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr);
961   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");
962 
963   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
964   ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr);
965   ierr = DMGetLocalToGlobalMapping(ex->da,&ltog);CHKERRQ(ierr);
966   ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &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,(HYPRE_Int *)ilower,(HYPRE_Int *)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,(HYPRE_Int *)ilower,(HYPRE_Int *)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 = PetscMalloc1(nvars*size,&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,(HYPRE_Int *)ilower,(HYPRE_Int *)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,(HYPRE_Int *)ilower,(HYPRE_Int *)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 #undef __FUNCT__
1093 #define __FUNCT__ "MatCreate_HYPRESStruct"
1094 PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B)
1095 {
1096   Mat_HYPRESStruct *ex;
1097   PetscErrorCode   ierr;
1098 
1099   PetscFunctionBegin;
1100   ierr         = PetscNewLog(B,&ex);CHKERRQ(ierr);
1101   B->data      = (void*)ex;
1102   B->rmap->bs  = 1;
1103   B->assembled = PETSC_FALSE;
1104 
1105   B->insertmode = NOT_SET_VALUES;
1106 
1107   B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct;
1108   B->ops->mult        = MatMult_HYPRESStruct;
1109   B->ops->zeroentries = MatZeroEntries_HYPRESStruct;
1110   B->ops->destroy     = MatDestroy_HYPRESStruct;
1111 
1112   ex->needsinitialization = PETSC_TRUE;
1113 
1114   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr);
1115   ierr = PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPRESStruct);CHKERRQ(ierr);
1116   ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr);
1117   PetscFunctionReturn(0);
1118 }
1119 
1120 
1121 
1122