Actual source code: mhyp.c

petsc-3.10.5 2019-03-28
Report Typos and Errors

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

 10: /* -----------------------------------------------------------------------------------------------------------------*/

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

 16:    Level: intermediate

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

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

 24: .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix()
 25: 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:   PetscErrorCode    ierr;
 31:   PetscInt          i,j,stencil,index[3],row,entries[7];
 32:   const PetscScalar *values = y;
 33:   Mat_HYPREStruct   *ex     = (Mat_HYPREStruct*) mat->data;

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

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

 78:   if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support");
 79:   PetscMemzero(values,7*sizeof(PetscScalar));
 80:   values[3] = d;
 81:   for (i=0; i<nrow; i++) {
 82:     row      = ex->gindices[irow[i]] - ex->rstart;
 83:     index[0] = ex->xs + (row % ex->nx);
 84:     index[1] = ex->ys + ((row/ex->nx) % ex->ny);
 85:     index[2] = ex->zs + (row/(ex->nxny));
 86:     PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,7,(HYPRE_Int *)entries,values));
 87:   }
 88:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
 89:   return(0);
 90: }

 92: PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat)
 93: {
 94:   PetscErrorCode  ierr;
 95:   PetscInt        indices[7] = {0,1,2,3,4,5,6};
 96:   Mat_HYPREStruct *ex        = (Mat_HYPREStruct*) mat->data;

 99:   /* hypre has no public interface to do this */
100:   PetscStackCallStandard(hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,(HYPRE_Int *)indices,0,1));
101:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
102:   return(0);
103: }

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

116:   MatGetDM(mat,(DM*)&da);
117:   ex->da = da;
118:   PetscObjectReference((PetscObject)da);

120:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);
121:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
122:   iupper[0] += ilower[0] - 1;
123:   iupper[1] += ilower[1] - 1;
124:   iupper[2] += ilower[2] - 1;

126:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
127:   ex->hbox.imin[0] = ilower[0];
128:   ex->hbox.imin[1] = ilower[1];
129:   ex->hbox.imin[2] = ilower[2];
130:   ex->hbox.imax[0] = iupper[0];
131:   ex->hbox.imax[1] = iupper[1];
132:   ex->hbox.imax[2] = iupper[2];

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

141:   sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0];
142:   PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,(HYPRE_Int *)sw));

144:   /* create the hypre stencil object and set its information */
145:   if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils");
146:   if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils");
147:   if (dim == 1) {
148:     PetscInt offsets[3][1] = {{-1},{0},{1}};
149:     ssize = 3;
150:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
151:     for (i=0; i<ssize; i++) {
152:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
153:     }
154:   } else if (dim == 2) {
155:     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
156:     ssize = 5;
157:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
158:     for (i=0; i<ssize; i++) {
159:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
160:     }
161:   } else if (dim == 3) {
162:     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}};
163:     ssize = 7;
164:     PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil));
165:     for (i=0; i<ssize; i++) {
166:       PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i]));
167:     }
168:   }

170:   /* create the HYPRE vector for rhs and solution */
171:   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb));
172:   PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx));
173:   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb));
174:   PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx));
175:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb));
176:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx));

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

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

196:   if (dim == 3) {
197:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d;
198:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPREStruct_3d;
199:     mat->ops->zeroentries    = MatZeroEntries_HYPREStruct_3d;

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

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

215: PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y)
216: {
217:   PetscErrorCode    ierr;
218:   const PetscScalar *xx;
219:   PetscScalar       *yy;
220:   PetscInt          ilower[3],iupper[3];
221:   Mat_HYPREStruct   *mx = (Mat_HYPREStruct*)(A->data);

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

226:   iupper[0] += ilower[0] - 1;
227:   iupper[1] += ilower[1] - 1;
228:   iupper[2] += ilower[2] - 1;

230:   /* copy x values over to hypre */
231:   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
232:   VecGetArrayRead(x,&xx);
233:   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,(PetscScalar*)xx));
234:   VecRestoreArrayRead(x,&xx);
235:   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
236:   PetscStackCallStandard(HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx));

238:   /* copy solution values back to PETSc */
239:   VecGetArray(y,&yy);
240:   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,yy));
241:   VecRestoreArray(y,&yy);
242:   return(0);
243: }

245: PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode)
246: {
247:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
248:   PetscErrorCode  ierr;

251:   PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat));
252:   /* PetscStackCallStandard(HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */
253:   return(0);
254: }

256: PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat)
257: {
259:   /* before the DMDA is set to the matrix the zero doesn't need to do anything */
260:   return(0);
261: }

263: PetscErrorCode MatDestroy_HYPREStruct(Mat mat)
264: {
265:   Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data;
266:   PetscErrorCode  ierr;

269:   PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat));
270:   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx));
271:   PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb));
272:   PetscObjectDereference((PetscObject)ex->da);
273:   MPI_Comm_free(&(ex->hcomm));
274:   PetscFree(ex);
275:   return(0);
276: }

278: PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B)
279: {
280:   Mat_HYPREStruct *ex;
281:   PetscErrorCode  ierr;

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

289:   B->insertmode = NOT_SET_VALUES;

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

297:   ex->needsinitialization = PETSC_TRUE;

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

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


309:    Level: intermediate

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

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

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

320: M*/

322: PetscErrorCode  MatSetValuesLocal_HYPRESStruct_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];
326:   const PetscScalar *values = y;
327:   Mat_HYPRESStruct  *ex     = (Mat_HYPRESStruct*) mat->data;

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

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 SETERRQ3(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] = ex->xs + (row % ex->nx);
374:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
375:       index[2] = ex->zs + (row/(ex->nxny));

377:       if (addv == ADD_VALUES) {
378:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
379:       } else {
380:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)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 SETERRQ3(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] = ex->xs + (row % ex->nx);
416:       index[1] = ex->ys + ((row/ex->nx) % ex->ny);
417:       index[2] = ex->zs + (row/(ex->nxny));

419:       if (addv == ADD_VALUES) {
420:         PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values));
421:       } else {
422:         PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)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:   PetscErrorCode   ierr;
434:   PetscInt         i,index[3];
435:   PetscScalar      **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,*entries;

446:   if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support");
447:   PetscMalloc1(7*nvars,&entries);

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

455:   for (i=0; i< nvars; i++) {
456:     PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));
457:     *(values[i]+3) = d;
458:   }

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

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

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

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

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

501:   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);
502:   {
503:     PetscInt    i,*entries,iupper[3],ilower[3];
504:     PetscScalar *values;


507:     for (i= 0; i< 3; i++) {
508:       ilower[i]= ex->hbox.imin[i];
509:       iupper[i]= ex->hbox.imax[i];
510:     }

512:     PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);
513:     for (i= 0; i< nvars*7; i++) entries[i]= i;
514:     PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));

516:     for (i= 0; i< nvars; i++) {
517:       PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,nvars*7,(HYPRE_Int *)entries,values));
518:     }
519:     PetscFree2(entries,values);
520:   }
521:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
522:   return(0);
523: }


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

540:   MatGetDM(mat,(DM*)&da);
541:   ex->da = da;
542:   PetscObjectReference((PetscObject)da);

544:   DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);
545:   DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
546:   iupper[0] += ilower[0] - 1;
547:   iupper[1] += ilower[1] - 1;
548:   iupper[2] += ilower[2] - 1;
549:   /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */
550:   ex->hbox.imin[0] = ilower[0];
551:   ex->hbox.imin[1] = ilower[1];
552:   ex->hbox.imin[2] = ilower[2];
553:   ex->hbox.imax[0] = iupper[0];
554:   ex->hbox.imax[1] = iupper[1];
555:   ex->hbox.imax[2] = iupper[2];

557:   ex->dofs_order = 0;

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

562:   /* create the hypre grid object and set its information */
563:   if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()");
564:   PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid));
565:   PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax));
566:   {
567:     HYPRE_SStructVariable *vartypes;
568:     PetscMalloc1(ex->nvars,&vartypes);
569:     for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL;
570:     PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes));
571:     PetscFree(vartypes);
572:   }
573:   PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid));

575:   sw[1] = sw[0];
576:   sw[2] = sw[1];
577:   /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */

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

583:   if (dim == 1) {
584:     PetscInt offsets[3][1] = {{-1},{0},{1}};
585:     PetscInt j, cnt;

587:     ssize = 3*(ex->nvars);
588:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
589:     cnt= 0;
590:     for (i = 0; i < (ex->nvars); i++) {
591:       for (j = 0; j < 3; j++) {
592:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
593:         cnt++;
594:       }
595:     }
596:   } else if (dim == 2) {
597:     PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}};
598:     PetscInt j, cnt;

600:     ssize = 5*(ex->nvars);
601:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
602:     cnt= 0;
603:     for (i= 0; i< (ex->nvars); i++) {
604:       for (j= 0; j< 5; j++) {
605:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
606:         cnt++;
607:       }
608:     }
609:   } else if (dim == 3) {
610:     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}};
611:     PetscInt j, cnt;

613:     ssize = 7*(ex->nvars);
614:     PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil));
615:     cnt= 0;
616:     for (i= 0; i< (ex->nvars); i++) {
617:       for (j= 0; j< 7; j++) {
618:         PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i));
619:         cnt++;
620:       }
621:     }
622:   }

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

627:   /* set the stencil graph. Note that each variable has the same graph. This means that each
628:      variable couples to all the other variable and with the same stencil pattern. */
629:   for (i= 0; i< (ex->nvars); i++) {
630:     PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil));
631:   }
632:   PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph));

634:   /* create the HYPRE sstruct vectors for rhs and solution */
635:   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b));
636:   PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x));
637:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b));
638:   PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x));
639:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b));
640:   PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x));

642:   /* create the hypre matrix object and set its information */
643:   PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat));
644:   PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid));
645:   PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil));
646:   if (ex->needsinitialization) {
647:     PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat));
648:     ex->needsinitialization = PETSC_FALSE;
649:   }

651:   /* set the global and local sizes of the matrix */
652:   DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);
653:   MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);
654:   PetscLayoutSetBlockSize(mat->rmap,dof);
655:   PetscLayoutSetBlockSize(mat->cmap,dof);
656:   PetscLayoutSetUp(mat->rmap);
657:   PetscLayoutSetUp(mat->cmap);
658:   mat->preallocated = PETSC_TRUE;

660:   if (dim == 3) {
661:     mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d;
662:     mat->ops->zerorowslocal  = MatZeroRowsLocal_HYPRESStruct_3d;
663:     mat->ops->zeroentries    = MatZeroEntries_HYPRESStruct_3d;

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

668:   /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */
669:   MatGetOwnershipRange(mat,&ex->rstart,NULL);
670:   DMGetLocalToGlobalMapping(ex->da,&ltog);
671:   ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);
672:   DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);

674:   ex->gnxgny    *= ex->gnx;
675:   ex->gnxgnygnz *= ex->gnxgny;

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

679:   ex->nxny   = ex->nx*ex->ny;
680:   ex->nxnynz = ex->nz*ex->nxny;
681:   return(0);
682: }

684: PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y)
685: {
686:   PetscErrorCode    ierr;
687:   const PetscScalar *xx;
688:   PetscScalar       *yy;
689:   PetscInt          ilower[3],iupper[3];
690:   Mat_HYPRESStruct  *mx     = (Mat_HYPRESStruct*)(A->data);
691:   PetscInt          ordering= mx->dofs_order;
692:   PetscInt          nvars   = mx->nvars;
693:   PetscInt          part    = 0;
694:   PetscInt          size;
695:   PetscInt          i;

698:   DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);
699:   iupper[0] += ilower[0] - 1;
700:   iupper[1] += ilower[1] - 1;
701:   iupper[2] += ilower[2] - 1;

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,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,(PetscScalar*)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,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,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,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,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,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,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;
762:   PetscErrorCode   ierr;

765:   PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat));
766:   return(0);
767: }

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

776: PetscErrorCode MatDestroy_HYPRESStruct(Mat mat)
777: {
778:   Mat_HYPRESStruct       *ex = (Mat_HYPRESStruct*) mat->data;
779:   PetscErrorCode         ierr;
780:   ISLocalToGlobalMapping ltog;

783:   DMGetLocalToGlobalMapping(ex->da,&ltog);
784:   ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **) &ex->gindices);
785:   PetscStackCallStandard(HYPRE_SStructGraphDestroy,(ex->ss_graph));
786:   PetscStackCallStandard(HYPRE_SStructMatrixDestroy,(ex->ss_mat));
787:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_x));
788:   PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_b));
789:   PetscObjectDereference((PetscObject)ex->da);
790:   MPI_Comm_free(&(ex->hcomm));
791:   PetscFree(ex);
792:   return(0);
793: }

795: PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B)
796: {
797:   Mat_HYPRESStruct *ex;
798:   PetscErrorCode   ierr;

801:   PetscNewLog(B,&ex);
802:   B->data      = (void*)ex;
803:   B->rmap->bs  = 1;
804:   B->assembled = PETSC_FALSE;

806:   B->insertmode = NOT_SET_VALUES;

808:   B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct;
809:   B->ops->mult        = MatMult_HYPRESStruct;
810:   B->ops->zeroentries = MatZeroEntries_HYPRESStruct;
811:   B->ops->destroy     = MatDestroy_HYPRESStruct;
812:   B->ops->setup       = MatSetUp_HYPRESStruct;

814:   ex->needsinitialization = PETSC_TRUE;

816:   MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));
817:   PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);
818:   return(0);
819: }