Actual source code: mhyp.c

      2: /*
      3:     Creates hypre ijmatrix from PETSc matrix
      4: */
      5: #include <petscsys.h>
      6: #include <petsc/private/petschypre.h>
      7: #include <petsc/private/matimpl.h>
      8: #include <petscdmda.h>
      9: #include <../src/dm/impls/da/hypre/mhyp.h>

     11: /* -----------------------------------------------------------------------------------------------------------------*/

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

     17:    Level: intermediate

     19:    Notes:
     20:     Unlike the more general support for blocks in hypre this allows only one block per process and requires the block
     21:           be defined by a DMDA.

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

     25: .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix()
     26: M*/

     28: PetscErrorCode  MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
     29: {
     30:   HYPRE_Int       index[3],entries[7];
     31:   PetscInt        i,j,stencil,row;
     32:   HYPRE_Complex   *values = (HYPRE_Complex*)y;
     33:   Mat_HYPREStruct *ex     = (Mat_HYPREStruct*) mat->data;

     36:   for (i=0; i<nrow; i++) {
     37:     for (j=0; j<ncol; j++) {
     38:       stencil = icol[j] - irow[i];
     39:       if (!stencil) {
     40:         entries[j] = 3;
     41:       } else if (stencil == -1) {
     42:         entries[j] = 2;
     43:       } else if (stencil == 1) {
     44:         entries[j] = 4;
     45:       } else if (stencil == -ex->gnx) {
     46:         entries[j] = 1;
     47:       } else if (stencil == ex->gnx) {
     48:         entries[j] = 5;
     49:       } else if (stencil == -ex->gnxgny) {
     50:         entries[j] = 0;
     51:       } else if (stencil == ex->gnxgny) {
     52:         entries[j] = 6;
     53:       } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
     54:     }
     55:     row      = ex->gindices[irow[i]] - ex->rstart;
     56:     index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
     57:     index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
     58:     index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));
     59:     if (addv == ADD_VALUES) {
     60:       PetscStackCallStandard(HYPRE_StructMatrixAddToValues,ex->hmat,index,ncol,entries,values);
     61:     } else {
     62:       PetscStackCallStandard(HYPRE_StructMatrixSetValues,ex->hmat,index,ncol,entries,values);
     63:     }
     64:     values += ncol;
     65:   }
     66:   return 0;
     67: }

     69: PetscErrorCode  MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
     70: {
     71:   HYPRE_Int       index[3],entries[7] = {0,1,2,3,4,5,6};
     72:   PetscInt        row,i;
     73:   HYPRE_Complex   values[7];
     74:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;

     77:   PetscArrayzero(values,7);
     78:   PetscHYPREScalarCast(d,&values[3]);
     79:   for (i=0; i<nrow; i++) {
     80:     row      = ex->gindices[irow[i]] - ex->rstart;
     81:     index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
     82:     index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
     83:     index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));
     84:     PetscStackCallStandard(HYPRE_StructMatrixSetValues,ex->hmat,index,7,entries,values);
     85:   }
     86:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,ex->hmat);
     87:   return 0;
     88: }

     90: PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat)
     91: {
     92:   HYPRE_Int       indices[7] = {0,1,2,3,4,5,6};
     93:   Mat_HYPREStruct *ex        = (Mat_HYPREStruct*) mat->data;

     95:   /* hypre has no public interface to do this */
     96:   PetscStackCallStandard(hypre_StructMatrixClearBoxValues,ex->hmat,&ex->hbox,7,indices,0,1);
     97:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,ex->hmat);
     98:   return 0;
     99: }

    101: static PetscErrorCode  MatSetUp_HYPREStruct(Mat mat)
    102: {
    103:   Mat_HYPREStruct        *ex = (Mat_HYPREStruct*) mat->data;
    104:   HYPRE_Int              sw[6];
    105:   HYPRE_Int              hlower[3],hupper[3];
    106:   PetscInt               dim,dof,psw,nx,ny,nz,ilower[3],iupper[3],ssize,i;
    107:   DMBoundaryType         px,py,pz;
    108:   DMDAStencilType        st;
    109:   ISLocalToGlobalMapping ltog;
    110:   DM                     da;

    112:   MatGetDM(mat,(DM*)&da);
    113:   ex->da = da;
    114:   PetscObjectReference((PetscObject)da);

    116:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&psw,&px,&py,&pz,&st);
    117:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);

    119:   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
    120:   iupper[0] += ilower[0] - 1;
    121:   iupper[1] += ilower[1] - 1;
    122:   iupper[2] += ilower[2] - 1;
    123:   hlower[0]  = (HYPRE_Int)ilower[0];
    124:   hlower[1]  = (HYPRE_Int)ilower[1];
    125:   hlower[2]  = (HYPRE_Int)ilower[2];
    126:   hupper[0]  = (HYPRE_Int)iupper[0];
    127:   hupper[1]  = (HYPRE_Int)iupper[1];
    128:   hupper[2]  = (HYPRE_Int)iupper[2];

    130:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
    131:   ex->hbox.imin[0] = hlower[0];
    132:   ex->hbox.imin[1] = hlower[1];
    133:   ex->hbox.imin[2] = hlower[2];
    134:   ex->hbox.imax[0] = hupper[0];
    135:   ex->hbox.imax[1] = hupper[1];
    136:   ex->hbox.imax[2] = hupper[2];

    138:   /* create the hypre grid object and set its information */
    141:   PetscStackCallStandard(HYPRE_StructGridCreate,ex->hcomm,dim,&ex->hgrid);
    142:   PetscStackCallStandard(HYPRE_StructGridSetExtents,ex->hgrid,hlower,hupper);
    143:   PetscStackCallStandard(HYPRE_StructGridAssemble,ex->hgrid);

    145:   sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0] = psw;
    146:   PetscStackCallStandard(HYPRE_StructGridSetNumGhost,ex->hgrid,sw);

    148:   /* create the hypre stencil object and set its information */
    151:   if (dim == 1) {
    152:     HYPRE_Int offsets[3][1] = {{-1},{0},{1}};
    153:     ssize = 3;
    154:     PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil);
    155:     for (i=0; i<ssize; i++) {
    156:       PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]);
    157:     }
    158:   } else if (dim == 2) {
    159:     HYPRE_Int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
    160:     ssize = 5;
    161:     PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil);
    162:     for (i=0; i<ssize; i++) {
    163:       PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]);
    164:     }
    165:   } else if (dim == 3) {
    166:     HYPRE_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}};
    167:     ssize = 7;
    168:     PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil);
    169:     for (i=0; i<ssize; i++) {
    170:       PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]);
    171:     }
    172:   }

    174:   /* create the HYPRE vector for rhs and solution */
    175:   PetscStackCallStandard(HYPRE_StructVectorCreate,ex->hcomm,ex->hgrid,&ex->hb);
    176:   PetscStackCallStandard(HYPRE_StructVectorCreate,ex->hcomm,ex->hgrid,&ex->hx);
    177:   PetscStackCallStandard(HYPRE_StructVectorInitialize,ex->hb);
    178:   PetscStackCallStandard(HYPRE_StructVectorInitialize,ex->hx);
    179:   PetscStackCallStandard(HYPRE_StructVectorAssemble,ex->hb);
    180:   PetscStackCallStandard(HYPRE_StructVectorAssemble,ex->hx);

    182:   /* create the hypre matrix object and set its information */
    183:   PetscStackCallStandard(HYPRE_StructMatrixCreate,ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat);
    184:   PetscStackCallStandard(HYPRE_StructGridDestroy,ex->hgrid);
    185:   PetscStackCallStandard(HYPRE_StructStencilDestroy,ex->hstencil);
    186:   if (ex->needsinitialization) {
    187:     PetscStackCallStandard(HYPRE_StructMatrixInitialize,ex->hmat);
    188:     ex->needsinitialization = PETSC_FALSE;
    189:   }

    191:   /* set the global and local sizes of the matrix */
    192:   DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);
    193:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
    194:   PetscLayoutSetBlockSize(mat->rmap,1);
    195:   PetscLayoutSetBlockSize(mat->cmap,1);
    196:   PetscLayoutSetUp(mat->rmap);
    197:   PetscLayoutSetUp(mat->cmap);
    198:   mat->preallocated = PETSC_TRUE;

    200:   if (dim == 3) {
    201:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
    202:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
    203:     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;

    205:     /*        MatZeroEntries_HYPREStruct_3d(mat); */
    206:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");

    208:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
    209:   MatGetOwnershipRange(mat,&ex->rstart,NULL);
    210:   DMGetLocalToGlobalMapping(ex->da,&ltog);
    211:   ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);
    212:   DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);
    213:   ex->gnxgny *= ex->gnx;
    214:   DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);
    215:   ex->nxny    = ex->nx*ex->ny;
    216:   return 0;
    217: }

    219: PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
    220: {
    221:   const PetscScalar *xx;
    222:   PetscScalar       *yy;
    223:   PetscInt          ilower[3],iupper[3];
    224:   HYPRE_Int         hlower[3],hupper[3];
    225:   Mat_HYPREStruct   *mx = (Mat_HYPREStruct*)(A->data);

    227:   DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
    228:   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
    229:   iupper[0] += ilower[0] - 1;
    230:   iupper[1] += ilower[1] - 1;
    231:   iupper[2] += ilower[2] - 1;
    232:   hlower[0]  = (HYPRE_Int)ilower[0];
    233:   hlower[1]  = (HYPRE_Int)ilower[1];
    234:   hlower[2]  = (HYPRE_Int)ilower[2];
    235:   hupper[0]  = (HYPRE_Int)iupper[0];
    236:   hupper[1]  = (HYPRE_Int)iupper[1];
    237:   hupper[2]  = (HYPRE_Int)iupper[2];

    239:   /* copy x values over to hypre */
    240:   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,mx->hb,0.0);
    241:   VecGetArrayRead(x,&xx);
    242:   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,mx->hb,hlower,hupper,(HYPRE_Complex*)xx);
    243:   VecRestoreArrayRead(x,&xx);
    244:   PetscStackCallStandard(HYPRE_StructVectorAssemble,mx->hb);
    245:   PetscStackCallStandard(HYPRE_StructMatrixMatvec,1.0,mx->hmat,mx->hb,0.0,mx->hx);

    247:   /* copy solution values back to PETSc */
    248:   VecGetArray(y,&yy);
    249:   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,mx->hx,hlower,hupper,(HYPRE_Complex*)yy);
    250:   VecRestoreArray(y,&yy);
    251:   return 0;
    252: }

    254: PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode)
    255: {
    256:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;

    258:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,ex->hmat);
    259:   /* PetscStackCallStandard(HYPRE_StructMatrixPrint,"dummy",ex->hmat,0); */
    260:   return 0;
    261: }

    263: PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat)
    264: {
    265:   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
    266:   return 0;
    267: }

    269: PetscErrorCode MatDestroy_HYPREStruct(Mat mat)
    270: {
    271:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;

    273:   PetscStackCallStandard(HYPRE_StructMatrixDestroy,ex->hmat);
    274:   PetscStackCallStandard(HYPRE_StructVectorDestroy,ex->hx);
    275:   PetscStackCallStandard(HYPRE_StructVectorDestroy,ex->hb);
    276:   PetscObjectDereference((PetscObject)ex->da);
    277:   MPI_Comm_free(&(ex->hcomm));
    278:   PetscFree(ex);
    279:   return 0;
    280: }

    282: PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B)
    283: {
    284:   Mat_HYPREStruct *ex;

    286:   PetscNewLog(B,&ex);
    287:   B->data      = (void*)ex;
    288:   B->rmap->bs  = 1;
    289:   B->assembled = PETSC_FALSE;

    291:   B->insertmode = NOT_SET_VALUES;

    293:   B->ops->assemblyend = MatAssemblyEnd_HYPREStruct;
    294:   B->ops->mult        = MatMult_HYPREStruct;
    295:   B->ops->zeroentries = MatZeroEntries_HYPREStruct;
    296:   B->ops->destroy     = MatDestroy_HYPREStruct;
    297:   B->ops->setup       = MatSetUp_HYPREStruct;

    299:   ex->needsinitialization = PETSC_TRUE;

    301:   MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));
    302:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);
    303:   return 0;
    304: }

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

    310:    Level: intermediate

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

    316:           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
    317:           be defined by a DMDA.

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

    321: M*/

    323: PetscErrorCode  MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
    324: {
    325:   HYPRE_Int         index[3],*entries;
    326:   PetscInt          i,j,stencil;
    327:   HYPRE_Complex     *values = (HYPRE_Complex*)y;
    328:   Mat_HYPRESStruct  *ex     = (Mat_HYPRESStruct*) mat->data;

    330:   PetscInt          part = 0;          /* Petsc sstruct interface only allows 1 part */
    331:   PetscInt          ordering;
    332:   PetscInt          grid_rank, to_grid_rank;
    333:   PetscInt          var_type, to_var_type;
    334:   PetscInt          to_var_entry = 0;
    335:   PetscInt          nvars= ex->nvars;
    336:   PetscInt          row;

    338:   PetscMalloc1(7*nvars,&entries);
    339:   ordering = ex->dofs_order;  /* ordering= 0   nodal ordering
    340:                                            1   variable ordering */
    341:   /* stencil entries are ordered by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ...  */
    342:   if (!ordering) {
    343:     for (i=0; i<nrow; i++) {
    344:       grid_rank= irow[i]/nvars;
    345:       var_type = (irow[i] % nvars);

    347:       for (j=0; j<ncol; j++) {
    348:         to_grid_rank= icol[j]/nvars;
    349:         to_var_type = (icol[j] % nvars);

    351:         to_var_entry= to_var_entry*7;
    352:         entries[j]  = to_var_entry;

    354:         stencil = to_grid_rank-grid_rank;
    355:         if (!stencil) {
    356:           entries[j] += 3;
    357:         } else if (stencil == -1) {
    358:           entries[j] += 2;
    359:         } else if (stencil == 1) {
    360:           entries[j] += 4;
    361:         } else if (stencil == -ex->gnx) {
    362:           entries[j] += 1;
    363:         } else if (stencil == ex->gnx) {
    364:           entries[j] += 5;
    365:         } else if (stencil == -ex->gnxgny) {
    366:           entries[j] += 0;
    367:         } else if (stencil == ex->gnxgny) {
    368:           entries[j] += 6;
    369:         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
    370:       }

    372:       row      = ex->gindices[grid_rank] - ex->rstart;
    373:       index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
    374:       index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
    375:       index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));

    377:       if (addv == ADD_VALUES) {
    378:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,ex->ss_mat,part,index,var_type,ncol,entries,values);
    379:       } else {
    380:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,ncol,entries,values);
    381:       }
    382:       values += ncol;
    383:     }
    384:   } else {
    385:     for (i=0; i<nrow; i++) {
    386:       var_type = irow[i]/(ex->gnxgnygnz);
    387:       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

    389:       for (j=0; j<ncol; j++) {
    390:         to_var_type = icol[j]/(ex->gnxgnygnz);
    391:         to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz);

    393:         to_var_entry= to_var_entry*7;
    394:         entries[j]  = to_var_entry;

    396:         stencil = to_grid_rank-grid_rank;
    397:         if (!stencil) {
    398:           entries[j] += 3;
    399:         } else if (stencil == -1) {
    400:           entries[j] += 2;
    401:         } else if (stencil == 1) {
    402:           entries[j] += 4;
    403:         } else if (stencil == -ex->gnx) {
    404:           entries[j] += 1;
    405:         } else if (stencil == ex->gnx) {
    406:           entries[j] += 5;
    407:         } else if (stencil == -ex->gnxgny) {
    408:           entries[j] += 0;
    409:         } else if (stencil == ex->gnxgny) {
    410:           entries[j] += 6;
    411:         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil);
    412:       }

    414:       row      = ex->gindices[grid_rank] - ex->rstart;
    415:       index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
    416:       index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
    417:       index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));

    419:       if (addv == ADD_VALUES) {
    420:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,ex->ss_mat,part,index,var_type,ncol,entries,values);
    421:       } else {
    422:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,ncol,entries,values);
    423:       }
    424:       values += ncol;
    425:     }
    426:   }
    427:   PetscFree(entries);
    428:   return 0;
    429: }

    431: PetscErrorCode  MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b)
    432: {
    433:   HYPRE_Int        index[3],*entries;
    434:   PetscInt         i;
    435:   HYPRE_Complex    **values;
    436:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;

    438:   PetscInt         part     = 0;      /* Petsc sstruct interface only allows 1 part */
    439:   PetscInt         ordering = ex->dofs_order;
    440:   PetscInt         grid_rank;
    441:   PetscInt         var_type;
    442:   PetscInt         nvars= ex->nvars;
    443:   PetscInt         row;

    446:   PetscMalloc1(7*nvars,&entries);

    448:   PetscMalloc1(nvars,&values);
    449:   PetscMalloc1(7*nvars*nvars,&values[0]);
    450:   for (i=1; i<nvars; i++) {
    451:     values[i] = values[i-1] + nvars*7;
    452:   }

    454:   for (i=0; i< nvars; i++) {
    455:     PetscArrayzero(values[i],nvars*7*sizeof(HYPRE_Complex));
    456:     PetscHYPREScalarCast(d,values[i]+3);
    457:   }

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

    461:   if (!ordering) {
    462:     for (i=0; i<nrow; i++) {
    463:       grid_rank = irow[i] / nvars;
    464:       var_type  = (irow[i] % nvars);

    466:       row      = ex->gindices[grid_rank] - ex->rstart;
    467:       index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
    468:       index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
    469:       index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));
    470:       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]);
    471:     }
    472:   } else {
    473:     for (i=0; i<nrow; i++) {
    474:       var_type = irow[i]/(ex->gnxgnygnz);
    475:       grid_rank= irow[i] - var_type*(ex->gnxgnygnz);

    477:       row      = ex->gindices[grid_rank] - ex->rstart;
    478:       index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx));
    479:       index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny));
    480:       index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny)));
    481:       PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]);
    482:     }
    483:   }
    484:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat);
    485:   PetscFree(values[0]);
    486:   PetscFree(values);
    487:   PetscFree(entries);
    488:   return 0;
    489: }

    491: PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat)
    492: {
    493:   Mat_HYPRESStruct *ex  = (Mat_HYPRESStruct*) mat->data;
    494:   PetscInt         nvars= ex->nvars;
    495:   PetscInt         size;
    496:   PetscInt         part= 0;   /* only one part */

    498:   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);
    499:   {
    500:     HYPRE_Int     i,*entries,iupper[3],ilower[3];
    501:     HYPRE_Complex *values;

    503:     for (i= 0; i< 3; i++) {
    504:       ilower[i] = ex->hbox.imin[i];
    505:       iupper[i] = ex->hbox.imax[i];
    506:     }

    508:     PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);
    509:     for (i= 0; i< nvars*7; i++) entries[i] = i;
    510:     PetscArrayzero(values,nvars*7*size);

    512:     for (i= 0; i< nvars; i++) {
    513:       PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values);
    514:     }
    515:     PetscFree2(entries,values);
    516:   }
    517:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat);
    518:   return 0;
    519: }

    521: static PetscErrorCode  MatSetUp_HYPRESStruct(Mat mat)
    522: {
    523:   Mat_HYPRESStruct       *ex = (Mat_HYPRESStruct*) mat->data;
    524:   PetscInt               dim,dof,sw[3],nx,ny,nz;
    525:   PetscInt               ilower[3],iupper[3],ssize,i;
    526:   DMBoundaryType         px,py,pz;
    527:   DMDAStencilType        st;
    528:   PetscInt               nparts= 1;  /* assuming only one part */
    529:   PetscInt               part  = 0;
    530:   ISLocalToGlobalMapping ltog;
    531:   DM                     da;

    533:   MatGetDM(mat,(DM*)&da);
    534:   ex->da = da;
    535:   PetscObjectReference((PetscObject)da);

    537:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);
    538:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
    539:   iupper[0] += ilower[0] - 1;
    540:   iupper[1] += ilower[1] - 1;
    541:   iupper[2] += ilower[2] - 1;
    542:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
    543:   ex->hbox.imin[0] = ilower[0];
    544:   ex->hbox.imin[1] = ilower[1];
    545:   ex->hbox.imin[2] = ilower[2];
    546:   ex->hbox.imax[0] = iupper[0];
    547:   ex->hbox.imax[1] = iupper[1];
    548:   ex->hbox.imax[2] = iupper[2];

    550:   ex->dofs_order = 0;

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

    555:   /* create the hypre grid object and set its information */
    557:   PetscStackCallStandard(HYPRE_SStructGridCreate,ex->hcomm,dim,nparts,&ex->ss_grid);
    558:   PetscStackCallStandard(HYPRE_SStructGridSetExtents,ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax);
    559:   {
    560:     HYPRE_SStructVariable *vartypes;
    561:     PetscMalloc1(ex->nvars,&vartypes);
    562:     for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
    563:     PetscStackCallStandard(HYPRE_SStructGridSetVariables,ex->ss_grid, part, ex->nvars,vartypes);
    564:     PetscFree(vartypes);
    565:   }
    566:   PetscStackCallStandard(HYPRE_SStructGridAssemble,ex->ss_grid);

    568:   sw[1] = sw[0];
    569:   sw[2] = sw[1];
    570:   /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,ex->ss_grid,sw); */

    572:   /* create the hypre stencil object and set its information */

    576:   if (dim == 1) {
    577:     HYPRE_Int offsets[3][1] = {{-1},{0},{1}};
    578:     PetscInt  j, cnt;

    580:     ssize = 3*(ex->nvars);
    581:     PetscStackCallStandard(HYPRE_SStructStencilCreate,dim,ssize,&ex->ss_stencil);
    582:     cnt= 0;
    583:     for (i = 0; i < (ex->nvars); i++) {
    584:       for (j = 0; j < 3; j++) {
    585:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i);
    586:         cnt++;
    587:       }
    588:     }
    589:   } else if (dim == 2) {
    590:     HYPRE_Int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
    591:     PetscInt  j, cnt;

    593:     ssize = 5*(ex->nvars);
    594:     PetscStackCallStandard(HYPRE_SStructStencilCreate,dim,ssize,&ex->ss_stencil);
    595:     cnt= 0;
    596:     for (i= 0; i< (ex->nvars); i++) {
    597:       for (j= 0; j< 5; j++) {
    598:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i);
    599:         cnt++;
    600:       }
    601:     }
    602:   } else if (dim == 3) {
    603:     HYPRE_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}};
    604:     PetscInt  j, cnt;

    606:     ssize = 7*(ex->nvars);
    607:     PetscStackCallStandard(HYPRE_SStructStencilCreate,dim,ssize,&ex->ss_stencil);
    608:     cnt= 0;
    609:     for (i= 0; i< (ex->nvars); i++) {
    610:       for (j= 0; j< 7; j++) {
    611:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i);
    612:         cnt++;
    613:       }
    614:     }
    615:   }

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

    620:   /* set the stencil graph. Note that each variable has the same graph. This means that each
    621:      variable couples to all the other variable and with the same stencil pattern. */
    622:   for (i= 0; i< (ex->nvars); i++) {
    623:     PetscStackCallStandard(HYPRE_SStructGraphSetStencil,ex->ss_graph,part,i,ex->ss_stencil);
    624:   }
    625:   PetscStackCallStandard(HYPRE_SStructGraphAssemble,ex->ss_graph);

    627:   /* create the HYPRE sstruct vectors for rhs and solution */
    628:   PetscStackCallStandard(HYPRE_SStructVectorCreate,ex->hcomm,ex->ss_grid,&ex->ss_b);
    629:   PetscStackCallStandard(HYPRE_SStructVectorCreate,ex->hcomm,ex->ss_grid,&ex->ss_x);
    630:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,ex->ss_b);
    631:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,ex->ss_x);
    632:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,ex->ss_b);
    633:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,ex->ss_x);

    635:   /* create the hypre matrix object and set its information */
    636:   PetscStackCallStandard(HYPRE_SStructMatrixCreate,ex->hcomm,ex->ss_graph,&ex->ss_mat);
    637:   PetscStackCallStandard(HYPRE_SStructGridDestroy,ex->ss_grid);
    638:   PetscStackCallStandard(HYPRE_SStructStencilDestroy,ex->ss_stencil);
    639:   if (ex->needsinitialization) {
    640:     PetscStackCallStandard(HYPRE_SStructMatrixInitialize,ex->ss_mat);
    641:     ex->needsinitialization = PETSC_FALSE;
    642:   }

    644:   /* set the global and local sizes of the matrix */
    645:   DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);
    646:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
    647:   PetscLayoutSetBlockSize(mat->rmap,dof);
    648:   PetscLayoutSetBlockSize(mat->cmap,dof);
    649:   PetscLayoutSetUp(mat->rmap);
    650:   PetscLayoutSetUp(mat->cmap);
    651:   mat->preallocated = PETSC_TRUE;

    653:   if (dim == 3) {
    654:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
    655:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
    656:     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;

    658:     /* MatZeroEntries_HYPRESStruct_3d(mat); */
    659:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently");

    661:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
    662:   MatGetOwnershipRange(mat,&ex->rstart,NULL);
    663:   DMGetLocalToGlobalMapping(ex->da,&ltog);
    664:   ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);
    665:   DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);

    667:   ex->gnxgny    *= ex->gnx;
    668:   ex->gnxgnygnz *= ex->gnxgny;

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

    672:   ex->nxny   = ex->nx*ex->ny;
    673:   ex->nxnynz = ex->nz*ex->nxny;
    674:   return 0;
    675: }

    677: PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y)
    678: {
    679:   const PetscScalar *xx;
    680:   PetscScalar       *yy;
    681:   HYPRE_Int         hlower[3],hupper[3];
    682:   PetscInt          ilower[3],iupper[3];
    683:   Mat_HYPRESStruct  *mx     = (Mat_HYPRESStruct*)(A->data);
    684:   PetscInt          ordering= mx->dofs_order;
    685:   PetscInt          nvars   = mx->nvars;
    686:   PetscInt          part    = 0;
    687:   PetscInt          size;
    688:   PetscInt          i;

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

    692:   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
    693:   iupper[0] += ilower[0] - 1;
    694:   iupper[1] += ilower[1] - 1;
    695:   iupper[2] += ilower[2] - 1;
    696:   hlower[0]  = (HYPRE_Int)ilower[0];
    697:   hlower[1]  = (HYPRE_Int)ilower[1];
    698:   hlower[2]  = (HYPRE_Int)ilower[2];
    699:   hupper[0]  = (HYPRE_Int)iupper[0];
    700:   hupper[1]  = (HYPRE_Int)iupper[1];
    701:   hupper[2]  = (HYPRE_Int)iupper[2];

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

    706:   /* copy x values over to hypre for variable ordering */
    707:   if (ordering) {
    708:     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
    709:     VecGetArrayRead(x,&xx);
    710:     for (i= 0; i< nvars; i++) {
    711:       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(xx+(size*i)));
    712:     }
    713:     VecRestoreArrayRead(x,&xx);
    714:     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
    715:     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);

    717:     /* copy solution values back to PETSc */
    718:     VecGetArray(y,&yy);
    719:     for (i= 0; i< nvars; i++) {
    720:       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(yy+(size*i)));
    721:     }
    722:     VecRestoreArray(y,&yy);
    723:   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
    724:     PetscScalar *z;
    725:     PetscInt    j, k;

    727:     PetscMalloc1(nvars*size,&z);
    728:     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
    729:     VecGetArrayRead(x,&xx);

    731:     /* transform nodal to hypre's variable ordering for sys_pfmg */
    732:     for (i= 0; i< size; i++) {
    733:       k= i*nvars;
    734:       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
    735:     }
    736:     for (i= 0; i< nvars; i++) {
    737:       PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
    738:     }
    739:     VecRestoreArrayRead(x,&xx);
    740:     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
    741:     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);

    743:     /* copy solution values back to PETSc */
    744:     VecGetArray(y,&yy);
    745:     for (i= 0; i< nvars; i++) {
    746:       PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
    747:     }
    748:     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
    749:     for (i= 0; i< size; i++) {
    750:       k= i*nvars;
    751:       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
    752:     }
    753:     VecRestoreArray(y,&yy);
    754:     PetscFree(z);
    755:   }
    756:   return 0;
    757: }

    759: PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode)
    760: {
    761:   Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data;

    763:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat);
    764:   return 0;
    765: }

    767: PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat)
    768: {
    769:   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
    770:   return 0;
    771: }

    773: PetscErrorCode MatDestroy_HYPRESStruct(Mat mat)
    774: {
    775:   Mat_HYPRESStruct       *ex = (Mat_HYPRESStruct*) mat->data;
    776:   ISLocalToGlobalMapping ltog;

    778:   DMGetLocalToGlobalMapping(ex->da,&ltog);
    779:   ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **) &ex->gindices);
    780:   PetscStackCallStandard(HYPRE_SStructGraphDestroy,ex->ss_graph);
    781:   PetscStackCallStandard(HYPRE_SStructMatrixDestroy,ex->ss_mat);
    782:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,ex->ss_x);
    783:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,ex->ss_b);
    784:   PetscObjectDereference((PetscObject)ex->da);
    785:   MPI_Comm_free(&(ex->hcomm));
    786:   PetscFree(ex);
    787:   return 0;
    788: }

    790: PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B)
    791: {
    792:   Mat_HYPRESStruct *ex;

    794:   PetscNewLog(B,&ex);
    795:   B->data      = (void*)ex;
    796:   B->rmap->bs  = 1;
    797:   B->assembled = PETSC_FALSE;

    799:   B->insertmode = NOT_SET_VALUES;

    801:   B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct;
    802:   B->ops->mult        = MatMult_HYPRESStruct;
    803:   B->ops->zeroentries = MatZeroEntries_HYPRESStruct;
    804:   B->ops->destroy     = MatDestroy_HYPRESStruct;
    805:   B->ops->setup       = MatSetUp_HYPRESStruct;

    807:   ex->needsinitialization = PETSC_TRUE;

    809:   MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));
    810:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);
    811:   return 0;
    812: }