Date: 2013-07-02T14:45:13+00:00

Actual source code: mhyp.c
petsc-3.4.2 2013-07-02

      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>

     12: PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat A_d, Mat A_o,HYPRE_IJMatrix ij)
     13: {
     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;

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

     57: PetscErrorCode MatHYPRE_IJMatrixCreate(Mat A,HYPRE_IJMatrix *ij)
     58: {
     60:   PetscInt       rstart,rend,cstart,cend;

     66:   MatSetUp(A);
     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:     PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&same);
     78:     if (same) {
     79:       MatMPIAIJGetSeqAIJ(A,&A_d,&A_o,&colmap);
     80:       MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);
     81:       return(0);
     82:     }
     83:     PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&same);
     84:     if (same) {
     85:       MatMPIBAIJGetSeqBAIJ(A,&A_d,&A_o,&colmap);
     86:       MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);
     87:       return(0);
     88:     }
     89:     PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&same);
     90:     if (same) {
     91:       MatHYPRE_IJMatrixPreallocate(A,NULL,*ij);
     92:       return(0);
     93:     }
     94:     PetscObjectTypeCompare((PetscObject)A,MATSEQBAIJ,&same);
     95:     if (same) {
     96:       MatHYPRE_IJMatrixPreallocate(A,NULL,*ij);
     97:       return(0);
     98:     }
     99:   }
    100:   return(0);
    101: }

    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: */

    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;

    120:   PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);
    121:   if (flg) {
    122:     MatHYPRE_IJMatrixFastCopy_MPIAIJ(A,ij);
    123:     return(0);
    124:   }
    125:   PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&flg);
    126:   if (flg) {
    127:     MatHYPRE_IJMatrixFastCopy_SeqAIJ(A,ij);
    128:     return(0);
    129:   }

    131:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
    132:   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
    133:   MatGetOwnershipRange(A,&rstart,&rend);
    134:   for (i=rstart; i<rend; i++) {
    135:     MatGetRow(A,i,&ncols,&cols,&values);
    136:     PetscStackCallStandard(HYPRE_IJMatrixSetValues,(ij,1,&ncols,&i,cols,values));
    137:     MatRestoreRow(A,i,&ncols,&cols,&values);
    138:   }
    139:   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
    140:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
    141:   return(0);
    142: }

    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.

    148: */
    149: #include <_hypre_IJ_mv.h>
    150: #include <HYPRE_IJ_mv.h>
    151: #include <../src/mat/impls/aij/mpi/mpiaij.h>

    155: PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat A,HYPRE_IJMatrix ij)
    156: {
    158:   Mat_SeqAIJ     *pdiag = (Mat_SeqAIJ*)A->data;

    160:   hypre_ParCSRMatrix    *par_matrix;
    161:   hypre_AuxParCSRMatrix *aux_matrix;
    162:   hypre_CSRMatrix       *hdiag;

    169:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
    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);

    175:   /*
    176:        this is the Hack part where we monkey directly with the hypre datastructures
    177:   */
    178:   PetscMemcpy(hdiag->i,pdiag->i,(A->rmap->n + 1)*sizeof(PetscInt));
    179:   PetscMemcpy(hdiag->j,pdiag->j,pdiag->nz*sizeof(PetscInt));
    180:   PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));

    182:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
    183:   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
    184:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
    185:   return(0);
    186: }

    190: PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat A,HYPRE_IJMatrix ij)
    191: {
    193:   Mat_MPIAIJ     *pA = (Mat_MPIAIJ*)A->data;
    194:   Mat_SeqAIJ     *pdiag,*poffd;
    195:   PetscInt       i,*garray = pA->garray,*jj,cstart,*pjj;

    197:   hypre_ParCSRMatrix    *par_matrix;
    198:   hypre_AuxParCSRMatrix *aux_matrix;
    199:   hypre_CSRMatrix       *hdiag,*hoffd;

    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:   MatGetOwnershipRange(A,&cstart,NULL);

    210:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
    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);

    217:   /*
    218:        this is the Hack part where we monkey directly with the hypre datastructures
    219:   */
    220:   PetscMemcpy(hdiag->i,pdiag->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
    221:   /* need to shift the diag column indices (hdiag->j) back to global numbering since hypre is expecting this */
    222:   jj  = hdiag->j;
    223:   pjj = pdiag->j;
    224:   for (i=0; i<pdiag->nz; i++) jj[i] = cstart + pjj[i];
    225:   PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));
    226:   PetscMemcpy(hoffd->i,poffd->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
    227:   /* need to move the offd column indices (hoffd->j) back to global numbering since hypre is expecting this
    228:      If we hacked a hypre a bit more we might be able to avoid this step */
    229:   jj  = hoffd->j;
    230:   pjj = poffd->j;
    231:   for (i=0; i<poffd->nz; i++) jj[i] = garray[pjj[i]];
    232:   PetscMemcpy(hoffd->data,poffd->a,poffd->nz*sizeof(PetscScalar));

    234:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
    235:   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(ij));
    236:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
    237:   return(0);
    238: }

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

    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>

    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;

    262:   PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);
    263:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Can only use with PETSc MPIAIJ matrices");
    264:   MatSetUp(A);

    266:   PetscLogEventBegin(MAT_Convert,A,0,0,0);
    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));

    274:   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(*ij));
    275:   PetscStackCall("hypre_IJMatrixTranslator",aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(*ij));

    277:   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;

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

    281:   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(*ij));
    282:   PetscLogEventEnd(MAT_Convert,A,0,0,0);
    283:   return(0);
    284: }

    286: /* -----------------------------------------------------------------------------------------------------------------*/

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

    292:    Level: intermediate

    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.

    297:           The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix()

    299: .seealso: MatCreate(), PCPFMG, MatSetupDM(), DMCreateMatrix()
    300: M*/

    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;

    313:   for (i=0; i<nrow; i++) {
    314:     for (j=0; j<ncol; j++) {
    315:       stencil = icol[j] - irow[i];
    316:       if (!stencil) {
    317:         entries[j] = 3;
    318:       } else if (stencil == -1) {
    319:         entries[j] = 2;
    320:       } else if (stencil == 1) {
    321:         entries[j] = 4;
    322:       } else if (stencil == -ex->gnx) {
    323:         entries[j] = 1;
    324:       } else if (stencil == ex->gnx) {
    325:         entries[j] = 5;
    326:       } else if (stencil == -ex->gnxgny) {
    327:         entries[j] = 0;
    328:       } else if (stencil == ex->gnxgny) {
    329:         entries[j] = 6;
    330:       } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
    331:     }
    332:     row      = ex->gindices[irow[i]] - ex->rstart;
    333:     index[0] = ex->xs + (row % ex->nx);
    334:     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    335:     index[2] = ex->zs + (row/(ex->nxny));
    336:     if (addv == ADD_VALUES) {
    337:       PetscStackCallStandard(HYPRE_StructMatrixAddToValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values));
    338:     } else {
    339:       PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values));
    340:     }
    341:     values += ncol;
    342:   }
    343:   return(0);
    344: }

    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;

    356:   if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support");
    357:   PetscMemzero(values,7*sizeof(PetscScalar));
    358:   values[3] = d;
    359:   for (i=0; i<nrow; i++) {
    360:     row      = ex->gindices[irow[i]] - ex->rstart;
    361:     index[0] = ex->xs + (row % ex->nx);
    362:     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    363:     index[2] = ex->zs + (row/(ex->nxny));
    364:     PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,index,7,entries,values));
    365:   }
    366:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
    367:   return(0);
    368: }

    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;

    379:   /* hypre has no public interface to do this */
    380:   PetscStackCallStandard(hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,indices,0,1));
    381:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
    382:   return(0);
    383: }

    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:   DMDABoundaryType px,py,pz;
    393:   DMDAStencilType  st;

    396:   ex->da = da;
    397:   PetscObjectReference((PetscObject)da);

    399:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);
    400:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
    401:   iupper[0] += ilower[0] - 1;
    402:   iupper[1] += ilower[1] - 1;
    403:   iupper[2] += ilower[2] - 1;

    405:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
    406:   ex->hbox.imin[0] = ilower[0];
    407:   ex->hbox.imin[1] = ilower[1];
    408:   ex->hbox.imin[2] = ilower[2];
    409:   ex->hbox.imax[0] = iupper[0];
    410:   ex->hbox.imax[1] = iupper[1];
    411:   ex->hbox.imax[2] = iupper[2];

    413:   /* create the hypre grid object and set its information */
    414:   if (dof > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems");
    415:   if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()");
    416:   PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid));
    417:   PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,ilower,iupper));
    418:   PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid));

    420:   sw[1] = sw[0];
    421:   sw[2] = sw[1];
    422:   PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,sw));

    424:   /* create the hypre stencil object and set its information */
    425:   if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils");
    426:   if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils");
    427:   if (dim == 1) {
    428:     PetscInt offsets[3][1] = {{-1},{0},{1}};
    429:     ssize = 3;
    430:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
    431:     for (i=0; i<ssize; i++) {
    432:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
    433:     }
    434:   } else if (dim == 2) {
    435:     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
    436:     ssize = 5;
    437:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
    438:     for (i=0; i<ssize; i++) {
    439:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
    440:     }
    441:   } else if (dim == 3) {
    442:     PetscInt offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
    443:     ssize = 7;
    444:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
    445:     for (i=0; i<ssize; i++) {
    446:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i]));
    447:     }
    448:   }

    450:   /* create the HYPRE vector for rhs and solution */
    451:   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb));
    452:   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx));
    453:   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb));
    454:   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx));
    455:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb));
    456:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx));

    458:   /* create the hypre matrix object and set its information */
    459:   PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat));
    460:   PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid));
    461:   PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil));
    462:   if (ex->needsinitialization) {
    463:     PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat));
    464:     ex->needsinitialization = PETSC_FALSE;
    465:   }

    467:   /* set the global and local sizes of the matrix */
    468:   DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);
    469:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
    470:   PetscLayoutSetBlockSize(mat->rmap,1);
    471:   PetscLayoutSetBlockSize(mat->cmap,1);
    472:   PetscLayoutSetUp(mat->rmap);
    473:   PetscLayoutSetUp(mat->cmap);

    475:   if (dim == 3) {
    476:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
    477:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
    478:     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;

    480:     MatZeroEntries_HYPREStruct_3d(mat);
    481:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");

    483:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
    484:   MatGetOwnershipRange(mat,&ex->rstart,NULL);
    485:   DMDAGetGlobalIndices(ex->da,NULL,&ex->gindices);
    486:   DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);
    487:   ex->gnxgny *= ex->gnx;
    488:   DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);
    489:   ex->nxny    = ex->nx*ex->ny;
    490:   return(0);
    491: }

    495: PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
    496: {
    497:   PetscErrorCode  ierr;
    498:   PetscScalar     *xx,*yy;
    499:   PetscInt        ilower[3],iupper[3];
    500:   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data);

    503:   DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);

    505:   iupper[0] += ilower[0] - 1;
    506:   iupper[1] += ilower[1] - 1;
    507:   iupper[2] += ilower[2] - 1;

    509:   /* copy x values over to hypre */
    510:   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
    511:   VecGetArray(x,&xx);
    512:   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,ilower,iupper,xx));
    513:   VecRestoreArray(x,&xx);
    514:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
    515:   PetscStackCallStandard(HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx));

    517:   /* copy solution values back to PETSc */
    518:   VecGetArray(y,&yy);
    519:   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,ilower,iupper,yy));
    520:   VecRestoreArray(y,&yy);
    521:   return(0);
    522: }

    526: PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode)
    527: {
    528:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
    529:   PetscErrorCode  ierr;

    532:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
    533:   /* PetscStackCallStandard(HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */
    534:   return(0);
    535: }

    539: PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat)
    540: {
    542:   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
    543:   return(0);
    544: }

    549: PetscErrorCode MatDestroy_HYPREStruct(Mat mat)
    550: {
    551:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
    552:   PetscErrorCode  ierr;

    555:   PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat));
    556:   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx));
    557:   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb));
    558:   return(0);
    559: }

    564: PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B)
    565: {
    566:   Mat_HYPREStruct *ex;
    567:   PetscErrorCode  ierr;

    570:   PetscNewLog(B,Mat_HYPREStruct,&ex);
    571:   B->data      = (void*)ex;
    572:   B->rmap->bs  = 1;
    573:   B->assembled = PETSC_FALSE;

    575:   B->insertmode = NOT_SET_VALUES;

    577:   B->ops->assemblyend = MatAssemblyEnd_HYPREStruct;
    578:   B->ops->mult        = MatMult_HYPREStruct;
    579:   B->ops->zeroentries = MatZeroEntries_HYPREStruct;
    580:   B->ops->destroy     = MatDestroy_HYPREStruct;

    582:   ex->needsinitialization = PETSC_TRUE;

    584:   MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));
    585:   PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPREStruct);
    586:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);
    587:   return(0);
    588: }

    590: /*MC
    591:    MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices
    592:           based on the hypre HYPRE_SStructMatrix.

    595:    Level: intermediate

    597:    Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured
    598:           grid objects, we will restrict the semi-struct objects to consist of only structured-grid components.

    600:           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
    601:           be defined by a DMDA.

    603:           The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix()

    605: M*/

    609: PetscErrorCode  MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
    610: {
    611:   PetscErrorCode    ierr;
    612:   PetscInt          i,j,stencil,index[3];
    613:   const PetscScalar *values = y;
    614:   Mat_HYPRESStruct  *ex     = (Mat_HYPRESStruct*) mat->data;

    616:   PetscInt part = 0;          /* Petsc sstruct interface only allows 1 part */
    617:   PetscInt ordering;
    618:   PetscInt grid_rank, to_grid_rank;
    619:   PetscInt var_type, to_var_type;
    620:   PetscInt to_var_entry = 0;

    622:   PetscInt nvars= ex->nvars;
    623:   PetscInt row,*entries;

    626:   PetscMalloc(7*nvars*sizeof(PetscInt),&entries);
    627:   ordering= ex->dofs_order;  /* ordering= 0   nodal ordering
    628:                                           1   variable ordering */
    629:   /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ...  */

    631:   if (!ordering) {
    632:     for (i=0; i<nrow; i++) {
    633:       grid_rank= irow[i]/nvars;
    634:       var_type = (irow[i] % nvars);

    636:       for (j=0; j<ncol; j++) {
    637:         to_grid_rank= icol[j]/nvars;
    638:         to_var_type = (icol[j] % nvars);

    640:         to_var_entry= to_var_entry*7;
    641:         entries[j]  = to_var_entry;

    643:         stencil = to_grid_rank-grid_rank;
    644:         if (!stencil) {
    645:           entries[j] += 3;
    646:         } else if (stencil == -1) {
    647:           entries[j] += 2;
    648:         } else if (stencil == 1) {
    649:           entries[j] += 4;
    650:         } else if (stencil == -ex->gnx) {
    651:           entries[j] += 1;
    652:         } else if (stencil == ex->gnx) {
    653:           entries[j] += 5;
    654:         } else if (stencil == -ex->gnxgny) {
    655:           entries[j] += 0;
    656:         } else if (stencil == ex->gnxgny) {
    657:           entries[j] += 6;
    658:         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
    659:       }

    661:       row      = ex->gindices[grid_rank] - ex->rstart;
    662:       index[0] = ex->xs + (row % ex->nx);
    663:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    664:       index[2] = ex->zs + (row/(ex->nxny));

    666:       if (addv == ADD_VALUES) {
    667:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
    668:       } else {
    669:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
    670:       }
    671:       values += ncol;
    672:     }
    673:   } else {
    674:     for (i=0; i<nrow; i++) {
    675:       var_type = irow[i]/(ex->gnxgnygnz);
    676:       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

    678:       for (j=0; j<ncol; j++) {
    679:         to_var_type = icol[j]/(ex->gnxgnygnz);
    680:         to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz);

    682:         to_var_entry= to_var_entry*7;
    683:         entries[j]  = to_var_entry;

    685:         stencil = to_grid_rank-grid_rank;
    686:         if (!stencil) {
    687:           entries[j] += 3;
    688:         } else if (stencil == -1) {
    689:           entries[j] += 2;
    690:         } else if (stencil == 1) {
    691:           entries[j] += 4;
    692:         } else if (stencil == -ex->gnx) {
    693:           entries[j] += 1;
    694:         } else if (stencil == ex->gnx) {
    695:           entries[j] += 5;
    696:         } else if (stencil == -ex->gnxgny) {
    697:           entries[j] += 0;
    698:         } else if (stencil == ex->gnxgny) {
    699:           entries[j] += 6;
    700:         } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
    701:       }

    703:       row      = ex->gindices[grid_rank] - ex->rstart;
    704:       index[0] = ex->xs + (row % ex->nx);
    705:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    706:       index[2] = ex->zs + (row/(ex->nxny));

    708:       if (addv == ADD_VALUES) {
    709:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
    710:       } else {
    711:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values));
    712:       }
    713:       values += ncol;
    714:     }
    715:   }
    716:   PetscFree(entries);
    717:   return(0);
    718: }

    722: PetscErrorCode  MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
    723: {
    724:   PetscErrorCode   ierr;
    725:   PetscInt         i,index[3];
    726:   PetscScalar      **values;
    727:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;

    729:   PetscInt part     = 0;      /* Petsc sstruct interface only allows 1 part */
    730:   PetscInt ordering = ex->dofs_order;
    731:   PetscInt grid_rank;
    732:   PetscInt var_type;
    733:   PetscInt nvars= ex->nvars;
    734:   PetscInt row,*entries;

    737:   if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support");
    738:   PetscMalloc(7*nvars*sizeof(PetscInt),&entries);

    740:   PetscMalloc(nvars*sizeof(PetscScalar*),&values);
    741:   PetscMalloc(7*nvars*nvars*sizeof(PetscScalar),&values[0]);
    742:   for (i=1; i<nvars; i++) {
    743:     values[i] = values[i-1] + nvars*7;
    744:   }

    746:   for (i=0; i< nvars; i++) {
    747:     PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));
    748:     *(values[i]+3) = d;
    749:   }

    751:   for (i= 0; i< nvars*7; i++) entries[i] = i;

    753:   if (!ordering) {
    754:     for (i=0; i<nrow; i++) {
    755:       grid_rank = irow[i] / nvars;
    756:       var_type  =(irow[i] % nvars);

    758:       row      = ex->gindices[grid_rank] - ex->rstart;
    759:       index[0] = ex->xs + (row % ex->nx);
    760:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    761:       index[2] = ex->zs + (row/(ex->nxny));
    762:       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]));
    763:     }
    764:   } else {
    765:     for (i=0; i<nrow; i++) {
    766:       var_type = irow[i]/(ex->gnxgnygnz);
    767:       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

    769:       row      = ex->gindices[grid_rank] - ex->rstart;
    770:       index[0] = ex->xs + (row % ex->nx);
    771:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
    772:       index[2] = ex->zs + (row/(ex->nxny));
    773:       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]));
    774:     }
    775:   }
    776:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
    777:   PetscFree(values[0]);
    778:   PetscFree(values);
    779:   PetscFree(entries);
    780:   return(0);
    781: }

    785: PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat)
    786: {
    787:   PetscErrorCode   ierr;
    788:   Mat_HYPRESStruct *ex  = (Mat_HYPRESStruct*) mat->data;
    789:   PetscInt         nvars= ex->nvars;
    790:   PetscInt         size;
    791:   PetscInt         part= 0;   /* only one part */

    794:   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);
    795:   {
    796:     PetscInt    i,*entries,iupper[3],ilower[3];
    797:     PetscScalar *values;

    800:     for (i= 0; i< 3; i++) {
    801:       ilower[i]= ex->hbox.imin[i];
    802:       iupper[i]= ex->hbox.imax[i];
    803:     }

    805:     PetscMalloc2(nvars*7,PetscInt,&entries,nvars*7*size,PetscScalar,&values);
    806:     for (i= 0; i< nvars*7; i++) entries[i]= i;
    807:     PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));

    809:     for (i= 0; i< nvars; i++) {
    810:       PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values));
    811:     }
    812:     PetscFree2(entries,values);
    813:   }
    814:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
    815:   return(0);
    816: }

    821: static PetscErrorCode  MatSetupDM_HYPRESStruct(Mat mat,DM da)
    822: {
    823:   PetscErrorCode   ierr;
    824:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
    825:   PetscInt         dim,dof,sw[3],nx,ny,nz;
    826:   PetscInt         ilower[3],iupper[3],ssize,i;
    827:   DMDABoundaryType px,py,pz;
    828:   DMDAStencilType  st;
    829:   PetscInt         nparts= 1;  /* assuming only one part */
    830:   PetscInt         part  = 0;

    833:   ex->da = da;
    834:   PetscObjectReference((PetscObject)da);

    836:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);
    837:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
    838:   iupper[0] += ilower[0] - 1;
    839:   iupper[1] += ilower[1] - 1;
    840:   iupper[2] += ilower[2] - 1;
    841:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
    842:   ex->hbox.imin[0] = ilower[0];
    843:   ex->hbox.imin[1] = ilower[1];
    844:   ex->hbox.imin[2] = ilower[2];
    845:   ex->hbox.imax[0] = iupper[0];
    846:   ex->hbox.imax[1] = iupper[1];
    847:   ex->hbox.imax[2] = iupper[2];

    849:   ex->dofs_order = 0;

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

    854:   /* create the hypre grid object and set its information */
    855:   if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()");
    856:   PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid));

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

    860:   {
    861:     HYPRE_SStructVariable *vartypes;
    862:     PetscMalloc(ex->nvars*sizeof(HYPRE_SStructVariable),&vartypes);
    863:     for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
    864:     PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes));
    865:     PetscFree(vartypes);
    866:   }
    867:   PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid));

    869:   sw[1] = sw[0];
    870:   sw[2] = sw[1];
    871:   /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */

    873:   /* create the hypre stencil object and set its information */
    874:   if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils");
    875:   if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils");

    877:   if (dim == 1) {
    878:     PetscInt offsets[3][1] = {{-1},{0},{1}};
    879:     PetscInt j, cnt;

    881:     ssize = 3*(ex->nvars);
    882:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
    883:     cnt= 0;
    884:     for (i = 0; i < (ex->nvars); i++) {
    885:       for (j = 0; j < 3; j++) {
    886:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
    887:         cnt++;
    888:       }
    889:     }
    890:   } else if (dim == 2) {
    891:     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
    892:     PetscInt j, cnt;

    894:     ssize = 5*(ex->nvars);
    895:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
    896:     cnt= 0;
    897:     for (i= 0; i< (ex->nvars); i++) {
    898:       for (j= 0; j< 5; j++) {
    899:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
    900:         cnt++;
    901:       }
    902:     }
    903:   } else if (dim == 3) {
    904:     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}};
    905:     PetscInt j, cnt;

    907:     ssize = 7*(ex->nvars);
    908:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
    909:     cnt= 0;
    910:     for (i= 0; i< (ex->nvars); i++) {
    911:       for (j= 0; j< 7; j++) {
    912:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i));
    913:         cnt++;
    914:       }
    915:     }
    916:   }

    918:   /* create the HYPRE graph */
    919:   PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph)));

    921:   /* set the stencil graph. Note that each variable has the same graph. This means that each
    922:      variable couples to all the other variable and with the same stencil pattern. */
    923:   for (i= 0; i< (ex->nvars); i++) {
    924:     PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil));
    925:   }
    926:   PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph));

    928:   /* create the HYPRE sstruct vectors for rhs and solution */
    929:   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b));
    930:   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x));
    931:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b));
    932:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x));
    933:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b));
    934:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x));

    936:   /* create the hypre matrix object and set its information */
    937:   PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat));
    938:   PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid));
    939:   PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil));
    940:   if (ex->needsinitialization) {
    941:     PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat));
    942:     ex->needsinitialization = PETSC_FALSE;
    943:   }

    945:   /* set the global and local sizes of the matrix */
    946:   DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);
    947:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
    948:   PetscLayoutSetBlockSize(mat->rmap,1);
    949:   PetscLayoutSetBlockSize(mat->cmap,1);
    950:   PetscLayoutSetUp(mat->rmap);
    951:   PetscLayoutSetUp(mat->cmap);

    953:   if (dim == 3) {
    954:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
    955:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
    956:     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;

    958:     MatZeroEntries_HYPRESStruct_3d(mat);
    959:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");

    961:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
    962:   MatGetOwnershipRange(mat,&ex->rstart,NULL);
    963:   DMDAGetGlobalIndices(ex->da,NULL,&ex->gindices);
    964:   DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);

    966:   ex->gnxgny    *= ex->gnx;
    967:   ex->gnxgnygnz *= ex->gnxgny;

    969:   DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);

    971:   ex->nxny   = ex->nx*ex->ny;
    972:   ex->nxnynz = ex->nz*ex->nxny;
    973:   return(0);
    974: }

    978: PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y)
    979: {
    980:   PetscErrorCode   ierr;
    981:   PetscScalar      *xx,*yy;
    982:   PetscInt         ilower[3],iupper[3];
    983:   Mat_HYPRESStruct *mx     = (Mat_HYPRESStruct*)(A->data);
    984:   PetscInt         ordering= mx->dofs_order;
    985:   PetscInt         nvars   = mx->nvars;
    986:   PetscInt         part    = 0;
    987:   PetscInt         size;
    988:   PetscInt         i;

    991:   DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
    992:   iupper[0] += ilower[0] - 1;
    993:   iupper[1] += ilower[1] - 1;
    994:   iupper[2] += ilower[2] - 1;

    996:   size= 1;
    997:   for (i = 0; i < 3; i++) size *= (iupper[i]-ilower[i]+1);

    999:   /* copy x values over to hypre for variable ordering */
    1000:   if (ordering) {
    1001:     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
    1002:     VecGetArray(x,&xx);
    1003:     for (i= 0; i< nvars; i++) {
    1004:       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,xx+(size*i)));
    1005:     }
    1006:     VecRestoreArray(x,&xx);
    1007:     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
    1008:     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));

    1010:     /* copy solution values back to PETSc */
    1011:     VecGetArray(y,&yy);
    1012:     for (i= 0; i< nvars; i++) {
    1013:       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,yy+(size*i)));
    1014:     }
    1015:     VecRestoreArray(y,&yy);
    1016:   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
    1017:     PetscScalar *z;
    1018:     PetscInt    j, k;

    1020:     PetscMalloc(nvars*size*sizeof(PetscScalar),&z);
    1021:     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
    1022:     VecGetArray(x,&xx);

    1024:     /* transform nodal to hypre's variable ordering for sys_pfmg */
    1025:     for (i= 0; i< size; i++) {
    1026:       k= i*nvars;
    1027:       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
    1028:     }
    1029:     for (i= 0; i< nvars; i++) {
    1030:       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,z+(size*i)));
    1031:     }
    1032:     VecRestoreArray(x,&xx);
    1033:     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
    1034:     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));

    1036:     /* copy solution values back to PETSc */
    1037:     VecGetArray(y,&yy);
    1038:     for (i= 0; i< nvars; i++) {
    1039:       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,z+(size*i)));
    1040:     }
    1041:     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
    1042:     for (i= 0; i< size; i++) {
    1043:       k= i*nvars;
    1044:       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
    1045:     }
    1046:     VecRestoreArray(y,&yy);
    1047:     PetscFree(z);
    1048:   }
    1049:   return(0);
    1050: }

    1054: PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode)
    1055: {
    1056:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
    1057:   PetscErrorCode   ierr;

    1060:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
    1061:   return(0);
    1062: }

    1066: PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat)
    1067: {
    1069:   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
    1070:   return(0);
    1071: }

    1076: PetscErrorCode MatDestroy_HYPRESStruct(Mat mat)
    1077: {
    1078:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;
    1079:   PetscErrorCode   ierr;

    1082:   PetscStackCallStandard(HYPRE_SStructGraphDestroy,(ex->ss_graph));
    1083:   PetscStackCallStandard(HYPRE_SStructMatrixDestroy,(ex->ss_mat));
    1084:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_x));
    1085:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_b));
    1086:   return(0);
    1087: }

    1091: PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B)
    1092: {
    1093:   Mat_HYPRESStruct *ex;
    1094:   PetscErrorCode   ierr;

    1097:   PetscNewLog(B,Mat_HYPRESStruct,&ex);
    1098:   B->data      = (void*)ex;
    1099:   B->rmap->bs  = 1;
    1100:   B->assembled = PETSC_FALSE;

    1102:   B->insertmode = NOT_SET_VALUES;

    1104:   B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct;
    1105:   B->ops->mult        = MatMult_HYPRESStruct;
    1106:   B->ops->zeroentries = MatZeroEntries_HYPRESStruct;
    1107:   B->ops->destroy     = MatDestroy_HYPRESStruct;

    1109:   ex->needsinitialization = PETSC_TRUE;

    1111:   MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));
    1112:   PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPRESStruct);
    1113:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);
    1114:   return(0);
    1115: }