Actual source code: mhyp.c

  1: #define PETSCMAT_DLL

  3: /*
  4:     Creates hypre ijmatrix from PETSc matrix
  5: */

 7:  #include private/matimpl.h
  8: #if defined(PETSC_HAVE_HYPRE)
 10: #include "HYPRE.h"
 11: #include "HYPRE_parcsr_ls.h"

 16: PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat A_d, Mat A_o,HYPRE_IJMatrix ij)
 17: {
 19:   PetscInt       i;
 20:   PetscInt       n_d,*ia_d,n_o,*ia_o;
 21:   PetscTruth     done_d=PETSC_FALSE,done_o=PETSC_FALSE;
 22:   PetscInt       *nnz_d=PETSC_NULL,*nnz_o=PETSC_NULL;
 23: 
 25:   if (A_d) { /* determine number of nonzero entries in local diagonal part */
 26:     MatGetRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);
 27:     if (done_d) {
 28:       PetscMalloc(n_d*sizeof(PetscInt),&nnz_d);
 29:       for (i=0; i<n_d; i++) {
 30:         nnz_d[i] = ia_d[i+1] - ia_d[i];
 31:       }
 32:     }
 33:     MatRestoreRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);
 34:   }
 35:   if (A_o) { /* determine number of nonzero entries in local off-diagonal part */
 36:     MatGetRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);
 37:     if (done_o) {
 38:       PetscMalloc(n_o*sizeof(PetscInt),&nnz_o);
 39:       for (i=0; i<n_o; i++) {
 40:         nnz_o[i] = ia_o[i+1] - ia_o[i];
 41:       }
 42:     }
 43:     MatRestoreRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);
 44:   }
 45:   if (done_d) {    /* set number of nonzeros in HYPRE IJ matrix */
 46:     if (!done_o) { /* only diagonal part */
 47:       PetscMalloc(n_d*sizeof(PetscInt),&nnz_o);
 48:       for (i=0; i<n_d; i++) {
 49:         nnz_o[i] = 0;
 50:       }
 51:     }
 52:     HYPRE_IJMatrixSetDiagOffdSizes(ij,nnz_d,nnz_o);
 53:     PetscFree(nnz_d);
 54:     PetscFree(nnz_o);
 55:   }
 56:   return(0);
 57: }


 62: PetscErrorCode MatHYPRE_IJMatrixCreate(Mat A,HYPRE_IJMatrix *ij)
 63: {
 65:   int            rstart,rend,cstart,cend;
 66: 
 71:   MatPreallocated(A);
 72:   rstart = A->rmap->rstart;
 73:   rend   = A->rmap->rend;
 74:   cstart = A->cmap->rstart;
 75:   cend   = A->cmap->rend;
 76:   HYPRE_IJMatrixCreate(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij);
 77:   HYPRE_IJMatrixSetObjectType(*ij,HYPRE_PARCSR);
 78:   {
 79:     PetscTruth  same;
 80:     Mat         A_d,A_o;
 81:     PetscInt    *colmap;
 82:     PetscTypeCompare((PetscObject)A,MATMPIAIJ,&same);
 83:     if (same) {
 84:       MatMPIAIJGetSeqAIJ(A,&A_d,&A_o,&colmap);
 85:       MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);
 86:       return(0);
 87:     }
 88:     PetscTypeCompare((PetscObject)A,MATMPIBAIJ,&same);
 89:     if (same) {
 90:       MatMPIBAIJGetSeqBAIJ(A,&A_d,&A_o,&colmap);
 91:       MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);
 92:       return(0);
 93:     }
 94:     PetscTypeCompare((PetscObject)A,MATSEQAIJ,&same);
 95:     if (same) {
 96:       MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);
 97:       return(0);
 98:     }
 99:     PetscTypeCompare((PetscObject)A,MATSEQBAIJ,&same);
100:     if (same) {
101:       MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);
102:       return(0);
103:     }
104:   }
105:   return(0);
106: }

110: /*
111:     Copies the data over (column indices, numerical values) to hypre matrix  
112: */

116: PetscErrorCode MatHYPRE_IJMatrixCopy(Mat A,HYPRE_IJMatrix ij)
117: {
118:   PetscErrorCode    ierr;
119:   PetscInt          i,rstart,rend,ncols;
120:   const PetscScalar *values;
121:   const PetscInt    *cols;
122:   PetscTruth        flg;

125:   PetscTypeCompare((PetscObject)A,MATMPIAIJ,&flg);
126:   if (flg) {
127:     MatHYPRE_IJMatrixFastCopy_MPIAIJ(A,ij);
128:     return(0);
129:   }
130:   PetscTypeCompare((PetscObject)A,MATSEQAIJ,&flg);
131:   if (flg) {
132:     MatHYPRE_IJMatrixFastCopy_SeqAIJ(A,ij);
133:     return(0);
134:   }

136:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
137:   HYPRE_IJMatrixInitialize(ij);
138:   MatGetOwnershipRange(A,&rstart,&rend);
139:   for (i=rstart; i<rend; i++) {
140:     MatGetRow(A,i,&ncols,&cols,&values);
141:     HYPRE_IJMatrixSetValues(ij,1,&ncols,&i,cols,values);
142:     MatRestoreRow(A,i,&ncols,&cols,&values);
143:   }
144:   HYPRE_IJMatrixAssemble(ij);
145:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
146:   return(0);
147: }

149: /*
150:     This copies the CSR format directly from the PETSc data structure to the hypre 
151:     data structure without calls to MatGetRow() or hypre's set values.

153: */
154: #include "_hypre_IJ_mv.h"
155: #include "HYPRE_IJ_mv.h"
156:  #include ../src/mat/impls/aij/mpi/mpiaij.h

160: PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat A,HYPRE_IJMatrix ij)
161: {
162:   PetscErrorCode        ierr;
163:   Mat_SeqAIJ            *pdiag = (Mat_SeqAIJ*)A->data;;

165:   hypre_ParCSRMatrix    *par_matrix;
166:   hypre_AuxParCSRMatrix *aux_matrix;
167:   hypre_CSRMatrix       *hdiag,*hoffd;


174:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
175:   HYPRE_IJMatrixInitialize(ij);
176:   par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij);
177:   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
178:   hdiag = hypre_ParCSRMatrixDiag(par_matrix);
179:   hoffd = hypre_ParCSRMatrixOffd(par_matrix);

181:   /* 
182:        this is the Hack part where we monkey directly with the hypre datastructures
183:   */

185:   PetscMemcpy(hdiag->i,pdiag->i,(A->rmap->n + 1)*sizeof(PetscInt));
186:   PetscMemcpy(hdiag->j,pdiag->j,pdiag->nz*sizeof(PetscInt));
187:   PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));

189:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
190:   HYPRE_IJMatrixAssemble(ij);
191:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
192:   return(0);
193: }

197: PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat A,HYPRE_IJMatrix ij)
198: {
199:   PetscErrorCode        ierr;
200:   Mat_MPIAIJ            *pA = (Mat_MPIAIJ*)A->data;
201:   Mat_SeqAIJ            *pdiag,*poffd;
202:   PetscInt              i,*garray = pA->garray,*jj,cstart,*pjj;

204:   hypre_ParCSRMatrix    *par_matrix;
205:   hypre_AuxParCSRMatrix *aux_matrix;
206:   hypre_CSRMatrix       *hdiag,*hoffd;

212:   pdiag = (Mat_SeqAIJ*) pA->A->data;
213:   poffd = (Mat_SeqAIJ*) pA->B->data;
214:   /* cstart is only valid for square MPIAIJ layed out in the usual way */
215:   MatGetOwnershipRange(A,&cstart,PETSC_NULL);

217:   PetscLogEventBegin(MAT_Convert,A,0,0,0);

219:   HYPRE_IJMatrixInitialize(ij);
220:   par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij);
221:   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
222:   hdiag = hypre_ParCSRMatrixDiag(par_matrix);
223:   hoffd = hypre_ParCSRMatrixOffd(par_matrix);

225:   /* 
226:        this is the Hack part where we monkey directly with the hypre datastructures
227:   */

229:   PetscMemcpy(hdiag->i,pdiag->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
230:   /* need to shift the diag column indices (hdiag->j) back to global numbering since hypre is expecting this */
231:   jj  = hdiag->j;
232:   pjj = pdiag->j;
233:   for (i=0; i<pdiag->nz; i++) {
234:     jj[i] = cstart + pjj[i];
235:   }
236:   PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));

238:   PetscMemcpy(hoffd->i,poffd->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
239:   /* need to move the offd column indices (hoffd->j) back to global numbering since hypre is expecting this
240:      If we hacked a hypre a bit more we might be able to avoid this step */
241:   jj  = hoffd->j;
242:   pjj = poffd->j;
243:   for (i=0; i<poffd->nz; i++) {
244:     jj[i] = garray[pjj[i]];
245:   }
246:   PetscMemcpy(hoffd->data,poffd->a,poffd->nz*sizeof(PetscScalar));

248:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
249:   HYPRE_IJMatrixAssemble(ij);
250:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
251:   return(0);
252: }

254: /*
255:     Does NOT copy the data over, instead uses DIRECTLY the pointers from the PETSc MPIAIJ format

257:     This is UNFINISHED and does NOT work! The problem is that hypre puts the diagonal entry first
258:     which will corrupt the PETSc data structure if we did this. Need a work around to this problem.
259: */
260: #include "_hypre_IJ_mv.h"
261: #include "HYPRE_IJ_mv.h"

265: PetscErrorCode MatHYPRE_IJMatrixLink(Mat A,HYPRE_IJMatrix *ij)
266: {
267:   PetscErrorCode        ierr;
268:   int                   rstart,rend,cstart,cend;
269:   PetscTruth            flg;
270:   hypre_ParCSRMatrix    *par_matrix;
271:   hypre_AuxParCSRMatrix *aux_matrix;

277:   PetscTypeCompare((PetscObject)A,MATMPIAIJ,&flg);
278:   if (!flg) SETERRQ(PETSC_ERR_SUP,"Can only use with PETSc MPIAIJ matrices");
279:   MatPreallocated(A);

281:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
282:   rstart = A->rmap->rstart;
283:   rend   = A->rmap->rend;
284:   cstart = A->cmap->rstart;
285:   cend   = A->cmap->rend;
286:   HYPRE_IJMatrixCreate(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij);
287:   HYPRE_IJMatrixSetObjectType(*ij,HYPRE_PARCSR);
288: 
289:   HYPRE_IJMatrixInitialize(*ij);
290:   par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(*ij);
291:   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(*ij);

293:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;

295:   /* this is the Hack part where we monkey directly with the hypre datastructures */

297:   HYPRE_IJMatrixAssemble(*ij);
298:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
299:   return(0);
300: }

302: /* -----------------------------------------------------------------------------------------------------------------*/

304: /*MC
305:    MATHYPRESTRUCT - MATHYPRESTRUCT = "hyprestruct" - A matrix type to be used for parallel sparse matrices
306:           based on the hypre HYPRE_StructMatrix.


309:    Notes: Unlike the more general support for blocks in hypre this allows only one block per process and requires the block
310:           be defined by a DA.

312:           The matrix needs a DA associated with it by either a call to MatSetDA() or if the matrix is obtained from DAGetMatrix()

314: .seealso: MatCreate(), PCPFMG, MatSetDA(), DAGetMatrix()
315: M*/

317:  #include petscda.h
318:  #include mhyp.h

322: PetscErrorCode  MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
323: {
324:   PetscErrorCode    ierr;
325:   PetscInt          i,j,stencil,index[3],row,entries[7];
326:   const PetscScalar *values = y;
327:   Mat_HYPREStruct   *ex = (Mat_HYPREStruct*) mat->data;

330:   for (i=0; i<nrow; i++) {
331:     for (j=0; j<ncol; j++) {
332:       stencil = icol[j] - irow[i];
333:       if (!stencil) {
334:         entries[j] = 3;
335:       } else if (stencil == -1) {
336:         entries[j] = 2;
337:       } else if (stencil == 1) {
338:         entries[j] = 4;
339:       } else if (stencil == -ex->gnx) {
340:         entries[j] = 1;
341:       } else if (stencil == ex->gnx) {
342:         entries[j] = 5;
343:       } else if (stencil == -ex->gnxgny) {
344:         entries[j] = 0;
345:       } else if (stencil == ex->gnxgny) {
346:         entries[j] = 6;
347:       } else SETERRQ3(PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
348:     }
349:     row = ex->gindices[irow[i]] - ex->rstart;
350:     index[0] = ex->xs + (row % ex->nx);
351:     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
352:     index[2] = ex->zs + (row/(ex->nxny));
353:     if (addv == ADD_VALUES) {
354:       HYPRE_StructMatrixAddToValues(ex->hmat,index,ncol,entries,(PetscScalar*)values);
355:     } else {
356:       HYPRE_StructMatrixSetValues(ex->hmat,index,ncol,entries,(PetscScalar*)values);
357:     }
358:     values += ncol;
359:   }
360:   return(0);
361: }

365: PetscErrorCode  MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d)
366: {
367:   PetscErrorCode  ierr;
368:   PetscInt        i,index[3],row,entries[7] = {0,1,2,3,4,5,6};
369:   PetscScalar     values[7];
370:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;

373:   PetscMemzero(values,7*sizeof(PetscScalar));
374:   values[3] = d;
375:   for (i=0; i<nrow; i++) {
376:     row = ex->gindices[irow[i]] - ex->rstart;
377:     index[0] = ex->xs + (row % ex->nx);
378:     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
379:     index[2] = ex->zs + (row/(ex->nxny));
380:     HYPRE_StructMatrixSetValues(ex->hmat,index,7,entries,values);
381:   }
382:   HYPRE_StructMatrixAssemble(ex->hmat);
383:   return(0);
384: }

388: PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat)
389: {
391:   PetscInt       indices[7] = {0,1,2,3,4,5,6};
392:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;

395:   /* hypre has no public interface to do this */
396:   hypre_StructMatrixClearBoxValues(ex->hmat,&ex->hbox,7,indices,0,1);
397:   HYPRE_StructMatrixAssemble(ex->hmat);
398:   return(0);
399: }

403: PetscErrorCode  MatSetDA_HYPREStruct(Mat mat,DA da)
404: {
405:   PetscErrorCode  ierr;
406:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
407:   PetscInt         dim,dof,sw[3],nx,ny,nz;
408:   int              ilower[3],iupper[3],ssize,i;
409:   DAPeriodicType   p;
410:   DAStencilType    st;

413:   ex->da = da;
414:   PetscObjectReference((PetscObject)da);

416:   DAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&p,&st);
417:   DAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
418:   iupper[0] += ilower[0] - 1;
419:   iupper[1] += ilower[1] - 1;
420:   iupper[2] += ilower[2] - 1;

422:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
423:   ex->hbox.imin[0] = ilower[0];
424:   ex->hbox.imin[1] = ilower[1];
425:   ex->hbox.imin[2] = ilower[2];
426:   ex->hbox.imax[0] = iupper[0];
427:   ex->hbox.imax[1] = iupper[1];
428:   ex->hbox.imax[2] = iupper[2];

430:   /* create the hypre grid object and set its information */
431:   if (dof > 1) SETERRQ(PETSC_ERR_SUP,"Currently only support for scalar problems");
432:   if (p) SETERRQ(PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()");
433:   HYPRE_StructGridCreate(ex->hcomm,dim,&ex->hgrid);

435:   HYPRE_StructGridSetExtents(ex->hgrid,ilower,iupper);
436:   HYPRE_StructGridAssemble(ex->hgrid);
437: 
438:   sw[1] = sw[0];
439:   sw[2] = sw[1];
440:   HYPRE_StructGridSetNumGhost(ex->hgrid,sw);

442:   /* create the hypre stencil object and set its information */
443:   if (sw[0] > 1) SETERRQ(PETSC_ERR_SUP,"Ask us to add support for wider stencils");
444:   if (st == DA_STENCIL_BOX) SETERRQ(PETSC_ERR_SUP,"Ask us to add support for box stencils");
445:   if (dim == 1) {
446:     int offsets[3][1] = {{-1},{0},{1}};
447:     ssize = 3;
448:     HYPRE_StructStencilCreate(dim,ssize,&ex->hstencil);
449:     for (i=0; i<ssize; i++) {
450:       HYPRE_StructStencilSetElement(ex->hstencil,i,offsets[i]);
451:     }
452:   } else if (dim == 2) {
453:     int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
454:     ssize = 5;
455:     HYPRE_StructStencilCreate(dim,ssize,&ex->hstencil);
456:     for (i=0; i<ssize; i++) {
457:       HYPRE_StructStencilSetElement(ex->hstencil,i,offsets[i]);
458:     }
459:   } else if (dim == 3) {
460:     int offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
461:     ssize = 7;
462:     HYPRE_StructStencilCreate(dim,ssize,&ex->hstencil);
463:     for (i=0; i<ssize; i++) {
464:       HYPRE_StructStencilSetElement(ex->hstencil,i,offsets[i]);
465:     }
466:   }
467: 
468:   /* create the HYPRE vector for rhs and solution */
469:   HYPRE_StructVectorCreate(ex->hcomm,ex->hgrid,&ex->hb);
470:   HYPRE_StructVectorCreate(ex->hcomm,ex->hgrid,&ex->hx);
471:   HYPRE_StructVectorInitialize(ex->hb);
472:   HYPRE_StructVectorInitialize(ex->hx);
473:   HYPRE_StructVectorAssemble(ex->hb);
474:   HYPRE_StructVectorAssemble(ex->hx);

476:   /* create the hypre matrix object and set its information */
477:   HYPRE_StructMatrixCreate(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat);
478:   HYPRE_StructGridDestroy(ex->hgrid);
479:   HYPRE_StructStencilDestroy(ex->hstencil);CHKERRQ(ierr)
480:   if (ex->needsinitialization) {
481:     HYPRE_StructMatrixInitialize(ex->hmat);
482:     ex->needsinitialization = PETSC_FALSE;
483:   }

485:   /* set the global and local sizes of the matrix */
486:   DAGetCorners(da,0,0,0,&nx,&ny,&nz);
487:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
488:   PetscLayoutSetBlockSize(mat->rmap,1);
489:   PetscLayoutSetBlockSize(mat->cmap,1);
490:   PetscLayoutSetUp(mat->rmap);
491:   PetscLayoutSetUp(mat->cmap);

493:   if (dim == 3) {
494:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
495:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
496:     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;
497:     MatZeroEntries_HYPREStruct_3d(mat);
498:   } else SETERRQ(PETSC_ERR_SUP,"Only support for 3d DA currently");

500:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
501:   MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);
502:   DAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);
503:   DAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);
504:   ex->gnxgny *= ex->gnx;
505:   DAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);
506:   ex->nxny = ex->nx*ex->ny;
507:   return(0);
508: }

512: PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
513: {
514:   PetscErrorCode  ierr;
515:   PetscScalar     *xx,*yy;
516:   int             ilower[3],iupper[3];
517:   Mat_HYPREStruct *mx = (Mat_HYPREStruct *)(A->data);

520:   DAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
521:   iupper[0] += ilower[0] - 1;
522:   iupper[1] += ilower[1] - 1;
523:   iupper[2] += ilower[2] - 1;

525:   /* copy x values over to hypre */
526:   HYPRE_StructVectorSetConstantValues(mx->hb,0.0);
527:   VecGetArray(x,&xx);
528:   HYPRE_StructVectorSetBoxValues(mx->hb,ilower,iupper,xx);
529:   VecRestoreArray(x,&xx);
530:   HYPRE_StructVectorAssemble(mx->hb);

532:   HYPRE_StructMatrixMatvec(1.0,mx->hmat,mx->hb,0.0,mx->hx);

534:   /* copy solution values back to PETSc */
535:   VecGetArray(y,&yy);
536:   HYPRE_StructVectorGetBoxValues(mx->hx,ilower,iupper,yy);
537:   VecRestoreArray(y,&yy);
538:   return(0);
539: }

543: PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode)
544: {
545:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
546:   PetscErrorCode   ierr;

549:   HYPRE_StructMatrixAssemble(ex->hmat);
550:   /* HYPRE_StructMatrixPrint("dummy",ex->hmat,0); */
551:   return(0);
552: }

556: PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat)
557: {
559:   /* before the DA is set to the matrix the zero doesn't need to do anything */
560:   return(0);
561: }


566: PetscErrorCode MatDestroy_HYPREStruct(Mat mat)
567: {
568:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
569:   PetscErrorCode  ierr;

572:   HYPRE_StructMatrixDestroy(ex->hmat);
573:   HYPRE_StructVectorDestroy(ex->hx);
574:   HYPRE_StructVectorDestroy(ex->hb);
575:   return(0);
576: }


582: PetscErrorCode  MatCreate_HYPREStruct(Mat B)
583: {
584:   Mat_HYPREStruct *ex;
585:   PetscErrorCode  ierr;

588:   PetscNewLog(B,Mat_HYPREStruct,&ex);
589:   B->data         = (void*)ex;
590:   B->rmap->bs     = 1;
591:   B->assembled    = PETSC_FALSE;
592:   B->mapping      = 0;

594:   B->insertmode   = NOT_SET_VALUES;

596:   B->ops->assemblyend    = MatAssemblyEnd_HYPREStruct;
597:   B->ops->mult           = MatMult_HYPREStruct;
598:   B->ops->zeroentries    = MatZeroEntries_HYPREStruct;
599:   B->ops->destroy        = MatDestroy_HYPREStruct;

601:   ex->needsinitialization = PETSC_TRUE;

603:   MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));
604:   PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetDA_C","MatSetDA_HYPREStruct",MatSetDA_HYPREStruct);
605:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);
606:   return(0);
607: }


611: /*MC
612:    MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices
613:           based on the hypre HYPRE_SStructMatrix.
614:   
615:   
616:    Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured
617:           grid objects, we will restrict the semi-struct objects to consist of only structured-grid components.

619:           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
620:           be defined by a DA.
621:   
622:           The matrix needs a DA associated with it by either a call to MatSetDA() or if the matrix is obtained from DAGetMatrix()
623:   
624: M*/

628: PetscErrorCode  MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
629: {
630:   PetscErrorCode    ierr;
631:   PetscInt          i,j,stencil,index[3];
632:   const PetscScalar *values = y;
633:   Mat_HYPRESStruct  *ex = (Mat_HYPRESStruct*) mat->data;

635:   int               part= 0; /* Petsc sstruct interface only allows 1 part */
636:   int               ordering;
637:   int               grid_rank, to_grid_rank;
638:   int               var_type, to_var_type;
639:   int               to_var_entry = 0;

641:   int               nvars= ex->nvars;
642:   PetscInt          row,*entries;

645:   PetscMalloc(7*nvars*sizeof(PetscInt),&entries);

647:   ordering= ex-> dofs_order; /* ordering= 0   nodal ordering
648:                                           1   variable ordering */
649:   /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ...  */

651:   if (!ordering)  /* nodal ordering */
652:   {
653:     for (i=0; i<nrow; i++) {
654:       grid_rank= irow[i]/nvars;
655:       var_type = (irow[i] % nvars);

657:       for (j=0; j<ncol; j++) {
658:         to_grid_rank= icol[j]/nvars;
659:         to_var_type = (icol[j] % nvars);

661:         to_var_entry= to_var_entry*7;
662:         entries[j]= to_var_entry;

664:         stencil = to_grid_rank-grid_rank;
665:         if (!stencil) {
666:           entries[j] += 3;
667:         } else if (stencil == -1) {
668:           entries[j] += 2;
669:         } else if (stencil == 1) {
670:           entries[j] += 4;
671:         } else if (stencil == -ex->gnx) {
672:           entries[j] += 1;
673:         } else if (stencil == ex->gnx) {
674:           entries[j] += 5;
675:         } else if (stencil == -ex->gnxgny) {
676:           entries[j] += 0;
677:         } else if (stencil == ex->gnxgny) {
678:           entries[j] += 6;
679:         } else SETERRQ3(PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
680:       }

682:       row = ex->gindices[grid_rank] - ex->rstart;
683:       index[0] = ex->xs + (row % ex->nx);
684:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
685:       index[2] = ex->zs + (row/(ex->nxny));

687:       if (addv == ADD_VALUES) {
688:         HYPRE_SStructMatrixAddToValues(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values);
689:       } else {
690:         HYPRE_SStructMatrixSetValues(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values);
691:       }
692:       values += ncol;
693:     }
694:   }

696:   else
697:   {
698:     for (i=0; i<nrow; i++) {
699:       var_type = irow[i]/(ex->gnxgnygnz);
700:       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

702:       for (j=0; j<ncol; j++) {
703:         to_var_type = icol[j]/(ex->gnxgnygnz);
704:         to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz);

706:         to_var_entry= to_var_entry*7;
707:         entries[j]= to_var_entry;

709:         stencil = to_grid_rank-grid_rank;
710:         if (!stencil) {
711:           entries[j] += 3;
712:         } else if (stencil == -1) {
713:           entries[j] += 2;
714:         } else if (stencil == 1) {
715:           entries[j] += 4;
716:         } else if (stencil == -ex->gnx) {
717:           entries[j] += 1;
718:         } else if (stencil == ex->gnx) {
719:           entries[j] += 5;
720:         } else if (stencil == -ex->gnxgny) {
721:           entries[j] += 0;
722:         } else if (stencil == ex->gnxgny) {
723:           entries[j] += 6;
724:         } else SETERRQ3(PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
725:       }

727:       row = ex->gindices[grid_rank] - ex->rstart;
728:       index[0] = ex->xs + (row % ex->nx);
729:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
730:       index[2] = ex->zs + (row/(ex->nxny));

732:       if (addv == ADD_VALUES) {
733:         HYPRE_SStructMatrixAddToValues(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values);
734:       } else {
735:         HYPRE_SStructMatrixSetValues(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values);
736:       }
737:       values += ncol;
738:     }

740:   }
741:   PetscFree(entries);
742:   return(0);
743: }

747: PetscErrorCode  MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d)
748: {
749:   PetscErrorCode    ierr;
750:   PetscInt          i,index[3];
751:   PetscScalar     **values;
752:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;

754:   int               part= 0; /* Petsc sstruct interface only allows 1 part */
755:   int               ordering= ex->dofs_order;
756:   int               grid_rank;
757:   int               var_type;
758:   int               nvars= ex->nvars;
759:   PetscInt          row,*entries;

762:   PetscMalloc(7*nvars*sizeof(PetscInt),&entries);

764:   PetscMalloc(nvars*sizeof(PetscScalar *),&values);
765:   PetscMalloc(7*nvars*nvars*sizeof(PetscScalar),&values[0]);
766:   for (i=1; i<nvars; i++) {
767:      values[i] = values[i-1] + nvars*7;
768:   }

770:   for (i=0; i< nvars; i++) {
771:      PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));
772:    *(values[i]+3)= d;
773:   }

775:   for (i= 0; i< nvars*7; i++) {
776:     entries[i]= i;
777:   }

779:   if (!ordering) {
780:     for (i=0; i<nrow; i++) {
781:        grid_rank= irow[i]/nvars;
782:        var_type = (irow[i] % nvars);

784:        row = ex->gindices[grid_rank] - ex->rstart;
785:        index[0] = ex->xs + (row % ex->nx);
786:        index[1] = ex->ys + ((row/ex->nx) % ex->ny);
787:        index[2] = ex->zs + (row/(ex->nxny));
788:        HYPRE_SStructMatrixSetValues(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]);
789:     }
790:   }
791: 
792:   else {
793:     for (i=0; i<nrow; i++) {
794:        var_type = irow[i]/(ex->gnxgnygnz);
795:        grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

797:        row = ex->gindices[grid_rank] - ex->rstart;
798:        index[0] = ex->xs + (row % ex->nx);
799:        index[1] = ex->ys + ((row/ex->nx) % ex->ny);
800:        index[2] = ex->zs + (row/(ex->nxny));
801:        HYPRE_SStructMatrixSetValues(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]);
802:     }
803:   }

805:   HYPRE_SStructMatrixAssemble(ex->ss_mat);

807:   PetscFree(values[0]);
808:   PetscFree(values);

810:   PetscFree(entries);
811:   return(0);
812: }

816: PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat)
817: {
818:   PetscErrorCode     ierr;
819:   Mat_HYPRESStruct  *ex = (Mat_HYPRESStruct*) mat->data;
820:   int                nvars= ex->nvars;
821:   int                size;
822:   int                part= 0; /* only one part */


826:   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);
827:   {
828:      PetscInt          i,*entries;
829:      PetscScalar      *values;
830:      int               iupper[3], ilower[3];
831: 
832:      for (i= 0; i< 3; i++) {
833:         ilower[i]= ex->hbox.imin[i];
834:         iupper[i]= ex->hbox.imax[i];
835:      }

837:      PetscMalloc2(nvars*7,PetscInt,&entries,nvars*7*size,PetscScalar,&values);
838:      for (i= 0; i< nvars*7; i++) {
839:         entries[i]= i;
840:      }

842:      PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));

844:      for (i= 0; i< nvars; i++) {
845:         HYPRE_SStructMatrixSetBoxValues(ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values);
846:      }

848:      PetscFree2(entries,values);
849:   }

851:   HYPRE_SStructMatrixAssemble(ex->ss_mat);

853:   return(0);
854: }


859: PetscErrorCode  MatSetDA_HYPRESStruct(Mat mat,DA da)
860: {
861:   PetscErrorCode    ierr;
862:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
863:   PetscInt          dim,dof,sw[3],nx,ny,nz;
864:   int               ilower[3],iupper[3],ssize,i;
865:   DAPeriodicType    p;
866:   DAStencilType     st;
867:   int               nparts= 1; /* assuming only one part */
868:   int               part  = 0;

871:   ex->da = da;
872:   PetscObjectReference((PetscObject)da);

874:   DAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&p,&st);
875:   DAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
876:   iupper[0] += ilower[0] - 1;
877:   iupper[1] += ilower[1] - 1;
878:   iupper[2] += ilower[2] - 1;
879:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
880:   ex->hbox.imin[0] = ilower[0];
881:   ex->hbox.imin[1] = ilower[1];
882:   ex->hbox.imin[2] = ilower[2];
883:   ex->hbox.imax[0] = iupper[0];
884:   ex->hbox.imax[1] = iupper[1];
885:   ex->hbox.imax[2] = iupper[2];

887:   ex->dofs_order   = 0;

889:   /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */
890:   ex->nvars= dof;

892:   /* create the hypre grid object and set its information */
893:   if (p) SETERRQ(PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()");
894:   HYPRE_SStructGridCreate(ex->hcomm,dim,nparts,&ex->ss_grid);

896:   HYPRE_SStructGridSetExtents(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax);

898:   {
899:     HYPRE_SStructVariable *vartypes;
900:     PetscMalloc(ex->nvars*sizeof(HYPRE_SStructVariable),&vartypes);
901:     for (i= 0; i< ex->nvars; i++) {
902:       vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
903:     }
904:     HYPRE_SStructGridSetVariables(ex->ss_grid, part, ex->nvars,vartypes);
905:     PetscFree(vartypes);
906:   }

908:   HYPRE_SStructGridAssemble(ex->ss_grid);

910:   sw[1] = sw[0];
911:   sw[2] = sw[1];
912: //  HYPRE_SStructGridSetNumGhost(ex->ss_grid,sw);

914:   /* create the hypre stencil object and set its information */
915:   if (sw[0] > 1) SETERRQ(PETSC_ERR_SUP,"Ask us to add support for wider stencils");
916:   if (st == DA_STENCIL_BOX) SETERRQ(PETSC_ERR_SUP,"Ask us to add support for box stencils");

918:   if (dim == 1) {
919:     int offsets[3][1] = {{-1},{0},{1}};
920:     int j, cnt;

922:     ssize = 3*(ex->nvars);
923:     HYPRE_SStructStencilCreate(dim,ssize,&ex->ss_stencil);
924:     cnt= 0;
925:     for (i= 0; i< (ex->nvars); i++) {
926:        for (j= 0; j< 3; j++) {
927:           HYPRE_SStructStencilSetEntry(ex->ss_stencil, cnt, offsets[j], i);
928:           cnt++;
929:        }
930:     }

932:   } else if (dim == 2) {
933:     int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
934:     int j, cnt;

936:     ssize = 5*(ex->nvars);
937:     HYPRE_SStructStencilCreate(dim,ssize,&ex->ss_stencil);
938:     cnt= 0;
939:     for (i= 0; i< (ex->nvars); i++) {
940:        for (j= 0; j< 5; j++) {
941:           HYPRE_SStructStencilSetEntry(ex->ss_stencil, cnt, offsets[j], i);
942:           cnt++;
943:        }
944:     }
945:   } else if (dim == 3) {
946:     int offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
947:     int j, cnt;

949:     ssize = 7*(ex->nvars);
950:     HYPRE_SStructStencilCreate(dim,ssize,&ex->ss_stencil);
951:     cnt= 0;
952:     for (i= 0; i< (ex->nvars); i++) {
953:        for (j= 0; j< 7; j++) {
954:           HYPRE_SStructStencilSetEntry(ex->ss_stencil, cnt, offsets[j], i);
955:           cnt++;
956:        }
957:     }
958:   }

960:   /* create the HYPRE graph */
961:   HYPRE_SStructGraphCreate(ex->hcomm, ex->ss_grid, &(ex->ss_graph));

963:   /* set the stencil graph. Note that each variable has the same graph. This means that each
964:      variable couples to all the other variable and with the same stencil pattern. */
965:   for (i= 0; i< (ex->nvars); i++) {
966:      HYPRE_SStructGraphSetStencil(ex->ss_graph,part,i,ex->ss_stencil);
967:   }
968:   ierr= HYPRE_SStructGraphAssemble(ex->ss_graph);

970:   /* create the HYPRE sstruct vectors for rhs and solution */
971:   HYPRE_SStructVectorCreate(ex->hcomm,ex->ss_grid,&ex->ss_b);
972:   HYPRE_SStructVectorCreate(ex->hcomm,ex->ss_grid,&ex->ss_x);
973:   HYPRE_SStructVectorInitialize(ex->ss_b);
974:   HYPRE_SStructVectorInitialize(ex->ss_x);
975:   HYPRE_SStructVectorAssemble(ex->ss_b);
976:   HYPRE_SStructVectorAssemble(ex->ss_x);

978:   /* create the hypre matrix object and set its information */
979:   HYPRE_SStructMatrixCreate(ex->hcomm,ex->ss_graph,&ex->ss_mat);
980:   HYPRE_SStructGridDestroy(ex->ss_grid);
981:   HYPRE_SStructStencilDestroy(ex->ss_stencil);CHKERRQ(ierr)
982:   if (ex->needsinitialization) {
983:     HYPRE_SStructMatrixInitialize(ex->ss_mat);
984:     ex->needsinitialization = PETSC_FALSE;
985:   }
986: 

988:   /* set the global and local sizes of the matrix */
989:   DAGetCorners(da,0,0,0,&nx,&ny,&nz);
990:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
991:   PetscLayoutSetBlockSize(mat->rmap,1);
992:   PetscLayoutSetBlockSize(mat->cmap,1);
993:   PetscLayoutSetUp(mat->rmap);
994:   PetscLayoutSetUp(mat->cmap);
995: 
996:   if (dim == 3) {
997:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
998:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
999:     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;
1000:     MatZeroEntries_HYPRESStruct_3d(mat);
1001:   } else SETERRQ(PETSC_ERR_SUP,"Only support for 3d DA currently");
1002: 
1003:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
1004:   MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);
1005:   DAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);
1006:   DAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);
1007:   ex->gnxgny    *= ex->gnx;
1008:   ex->gnxgnygnz *= ex->gnxgny;
1009:   DAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);
1010:   ex->nxny   = ex->nx*ex->ny;
1011:   ex->nxnynz = ex->nz*ex->nxny;
1012:   return(0);
1013: }
1014: 
1017: PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y)
1018: {
1019:   PetscErrorCode    ierr;
1020:   PetscScalar      *xx,*yy;
1021:   int               ilower[3],iupper[3];
1022:   Mat_HYPRESStruct *mx = (Mat_HYPRESStruct *)(A->data);
1023:   int               ordering= mx->dofs_order;
1024:   int               nvars= mx->nvars;
1025:   int               part= 0;
1026:   int               size;
1027:   int               i;
1028: 
1030:   DAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
1031:   iupper[0] += ilower[0] - 1;
1032:   iupper[1] += ilower[1] - 1;
1033:   iupper[2] += ilower[2] - 1;

1035:   size= 1;
1036:   for (i= 0; i< 3; i++) {
1037:      size*= (iupper[i]-ilower[i]+1);
1038:   }

1040:   /* copy x values over to hypre for variable ordering */
1041:   if (ordering) {
1042:      HYPRE_SStructVectorSetConstantValues(mx->ss_b,0.0);
1043:      VecGetArray(x,&xx);
1044:      for (i= 0; i< nvars; i++) {
1045:         HYPRE_SStructVectorSetBoxValues(mx->ss_b,part,ilower,iupper,i,xx+(size*i));
1046:      }
1047:      VecRestoreArray(x,&xx);
1048:      HYPRE_SStructVectorAssemble(mx->ss_b);
1049: 
1050:      HYPRE_SStructMatrixMatvec(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);

1052:      /* copy solution values back to PETSc */
1053:      VecGetArray(y,&yy);
1054:      for (i= 0; i< nvars; i++) {
1055:         HYPRE_SStructVectorGetBoxValues(mx->ss_x,part,ilower,iupper,i,yy+(size*i));
1056:      }
1057:      VecRestoreArray(y,&yy);
1058:   }

1060:   else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
1061:      PetscScalar     *z;
1062:      int              j, k;

1064:      PetscMalloc(nvars*size*sizeof(PetscScalar),&z);
1065:      HYPRE_SStructVectorSetConstantValues(mx->ss_b,0.0);
1066:      VecGetArray(x,&xx);

1068:      /* transform nodal to hypre's variable ordering for sys_pfmg */
1069:      for (i= 0; i< size; i++) {
1070:         k= i*nvars;
1071:         for (j= 0; j< nvars; j++) {
1072:            z[j*size+i]= xx[k+j];
1073:         }
1074:      }
1075:      for (i= 0; i< nvars; i++) {
1076:         HYPRE_SStructVectorSetBoxValues(mx->ss_b,part,ilower,iupper,i,z+(size*i));
1077:      }
1078:      VecRestoreArray(x,&xx);

1080:      HYPRE_SStructVectorAssemble(mx->ss_b);
1081: 
1082:      HYPRE_SStructMatrixMatvec(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);
1083: 
1084:      /* copy solution values back to PETSc */
1085:      VecGetArray(y,&yy);
1086:      for (i= 0; i< nvars; i++) {
1087:         HYPRE_SStructVectorGetBoxValues(mx->ss_x,part,ilower,iupper,i,z+(size*i));
1088:      }
1089:      /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
1090:      for (i= 0; i< size; i++) {
1091:         k= i*nvars;
1092:         for (j= 0; j< nvars; j++) {
1093:            yy[k+j]= z[j*size+i];
1094:         }
1095:      }
1096:      VecRestoreArray(y,&yy);

1098:      PetscFree(z);
1099:   }

1101:   return(0);
1102: }

1106: PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode)
1107: {
1108:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
1109:   PetscErrorCode   ierr;

1112: printf("look 1\n");
1113:   HYPRE_SStructMatrixAssemble(ex->ss_mat);
1114: printf("look 2\n");
1115:   return(0);
1116: }

1120: PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat)
1121: {
1123:   /* before the DA is set to the matrix the zero doesn't need to do anything */
1124:   return(0);
1125: }


1130: PetscErrorCode MatDestroy_HYPRESStruct(Mat mat)
1131: {
1132:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
1133:   PetscErrorCode  ierr;

1136:   HYPRE_SStructGraphDestroy(ex->ss_graph);
1137:   HYPRE_SStructMatrixDestroy(ex->ss_mat);
1138:   HYPRE_SStructVectorDestroy(ex->ss_x);
1139:   HYPRE_SStructVectorDestroy(ex->ss_b);
1140:   return(0);
1141: }

1146: PetscErrorCode  MatCreate_HYPRESStruct(Mat B)
1147: {
1148:   Mat_HYPRESStruct *ex;
1149:   PetscErrorCode   ierr;

1152:   PetscNewLog(B,Mat_HYPRESStruct,&ex);
1153:   B->data         = (void*)ex;
1154:   B->rmap->bs     = 1;
1155:   B->assembled    = PETSC_FALSE;
1156:   B->mapping      = 0;

1158:   B->insertmode   = NOT_SET_VALUES;

1160:   B->ops->assemblyend    = MatAssemblyEnd_HYPRESStruct;
1161:   B->ops->mult           = MatMult_HYPRESStruct;
1162:   B->ops->zeroentries    = MatZeroEntries_HYPRESStruct;
1163:   B->ops->destroy        = MatDestroy_HYPRESStruct;

1165:   ex->needsinitialization = PETSC_TRUE;
1166: 
1167:   MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));
1168:   PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetDA_C","MatSetDA_HYPRESStruct",MatSetDA_HYPRESStruct);
1169:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);
1170:   return(0);
1171: }

1174: #endif