1f4bdf6c4SBarry Smith 2f4bdf6c4SBarry Smith /* 3f4bdf6c4SBarry Smith Creates hypre ijmatrix from PETSc matrix 4f4bdf6c4SBarry Smith */ 5c6db04a5SJed Brown #include <petscsys.h> 6af0996ceSBarry Smith #include <petsc/private/matimpl.h> 7c6db04a5SJed Brown #include <petscdmda.h> /*I "petscdmda.h" I*/ 8c6db04a5SJed Brown #include <../src/dm/impls/da/hypre/mhyp.h> 9f4bdf6c4SBarry Smith 10f4bdf6c4SBarry Smith /* -----------------------------------------------------------------------------------------------------------------*/ 11f4bdf6c4SBarry Smith 12f4bdf6c4SBarry Smith /*MC 13f4bdf6c4SBarry Smith MATHYPRESTRUCT - MATHYPRESTRUCT = "hyprestruct" - A matrix type to be used for parallel sparse matrices 14f4bdf6c4SBarry Smith based on the hypre HYPRE_StructMatrix. 15f4bdf6c4SBarry Smith 16f4bdf6c4SBarry Smith Level: intermediate 17f4bdf6c4SBarry Smith 18*95452b02SPatrick Sanan Notes: 19*95452b02SPatrick Sanan Unlike the more general support for blocks in hypre this allows only one block per process and requires the block 20f4bdf6c4SBarry Smith be defined by a DMDA. 21f4bdf6c4SBarry Smith 2259cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 23f4bdf6c4SBarry Smith 2459cb773eSBarry Smith .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix() 25f4bdf6c4SBarry Smith M*/ 26f4bdf6c4SBarry Smith 27f4bdf6c4SBarry Smith 28f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 29f4bdf6c4SBarry Smith { 30f4bdf6c4SBarry Smith PetscErrorCode ierr; 31f4bdf6c4SBarry Smith PetscInt i,j,stencil,index[3],row,entries[7]; 32f4bdf6c4SBarry Smith const PetscScalar *values = y; 33f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 34f4bdf6c4SBarry Smith 35f4bdf6c4SBarry Smith PetscFunctionBegin; 3659cb773eSBarry Smith if (PetscUnlikely(ncol > 7)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"ncol %D > 7 too large",ncol); 37f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 38f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 39f4bdf6c4SBarry Smith stencil = icol[j] - irow[i]; 40f4bdf6c4SBarry Smith if (!stencil) { 41f4bdf6c4SBarry Smith entries[j] = 3; 42f4bdf6c4SBarry Smith } else if (stencil == -1) { 43f4bdf6c4SBarry Smith entries[j] = 2; 44f4bdf6c4SBarry Smith } else if (stencil == 1) { 45f4bdf6c4SBarry Smith entries[j] = 4; 46f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 47f4bdf6c4SBarry Smith entries[j] = 1; 48f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 49f4bdf6c4SBarry Smith entries[j] = 5; 50f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 51f4bdf6c4SBarry Smith entries[j] = 0; 52f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 53f4bdf6c4SBarry Smith entries[j] = 6; 54f4bdf6c4SBarry Smith } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 55f4bdf6c4SBarry Smith } 56f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 57f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 58f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 59f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 60f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 618b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAddToValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 62f4bdf6c4SBarry Smith } else { 638b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 64f4bdf6c4SBarry Smith } 65f4bdf6c4SBarry Smith values += ncol; 66f4bdf6c4SBarry Smith } 67f4bdf6c4SBarry Smith PetscFunctionReturn(0); 68f4bdf6c4SBarry Smith } 69f4bdf6c4SBarry Smith 70f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 71f4bdf6c4SBarry Smith { 72f4bdf6c4SBarry Smith PetscErrorCode ierr; 73f4bdf6c4SBarry Smith PetscInt i,index[3],row,entries[7] = {0,1,2,3,4,5,6}; 74f4bdf6c4SBarry Smith PetscScalar values[7]; 75f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 76f4bdf6c4SBarry Smith 77f4bdf6c4SBarry Smith PetscFunctionBegin; 78ce94432eSBarry Smith if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 79f4bdf6c4SBarry Smith ierr = PetscMemzero(values,7*sizeof(PetscScalar));CHKERRQ(ierr); 80f4bdf6c4SBarry Smith values[3] = d; 81f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 82f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 83f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 84f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 85f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 868b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,7,(HYPRE_Int *)entries,values)); 87f4bdf6c4SBarry Smith } 88fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 89f4bdf6c4SBarry Smith PetscFunctionReturn(0); 90f4bdf6c4SBarry Smith } 91f4bdf6c4SBarry Smith 92f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat) 93f4bdf6c4SBarry Smith { 94f4bdf6c4SBarry Smith PetscErrorCode ierr; 95f4bdf6c4SBarry Smith PetscInt indices[7] = {0,1,2,3,4,5,6}; 96f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 97f4bdf6c4SBarry Smith 98f4bdf6c4SBarry Smith PetscFunctionBegin; 99f4bdf6c4SBarry Smith /* hypre has no public interface to do this */ 1008b1f7689SBarry Smith PetscStackCallStandard(hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,(HYPRE_Int *)indices,0,1)); 101fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 102f4bdf6c4SBarry Smith PetscFunctionReturn(0); 103f4bdf6c4SBarry Smith } 104f4bdf6c4SBarry Smith 10559cb773eSBarry Smith static PetscErrorCode MatSetUp_HYPREStruct(Mat mat) 106f4bdf6c4SBarry Smith { 107f4bdf6c4SBarry Smith PetscErrorCode ierr; 108f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 10959cb773eSBarry Smith PetscInt dim,dof,sw[6],nx,ny,nz,ilower[3],iupper[3],ssize,i; 110bff4a2f0SMatthew G. Knepley DMBoundaryType px,py,pz; 111f4bdf6c4SBarry Smith DMDAStencilType st; 112565245c5SBarry Smith ISLocalToGlobalMapping ltog; 11359cb773eSBarry Smith DM da; 114f4bdf6c4SBarry Smith 115f4bdf6c4SBarry Smith PetscFunctionBegin; 11659cb773eSBarry Smith ierr = MatGetDM(mat,(DM*)&da);CHKERRQ(ierr); 117f4bdf6c4SBarry Smith ex->da = da; 118f4bdf6c4SBarry Smith ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 119f4bdf6c4SBarry Smith 1207ab44359SJed Brown ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 121f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 122f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 123f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 124f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 125f4bdf6c4SBarry Smith 126f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 127f4bdf6c4SBarry Smith ex->hbox.imin[0] = ilower[0]; 128f4bdf6c4SBarry Smith ex->hbox.imin[1] = ilower[1]; 129f4bdf6c4SBarry Smith ex->hbox.imin[2] = ilower[2]; 130f4bdf6c4SBarry Smith ex->hbox.imax[0] = iupper[0]; 131f4bdf6c4SBarry Smith ex->hbox.imax[1] = iupper[1]; 132f4bdf6c4SBarry Smith ex->hbox.imax[2] = iupper[2]; 133f4bdf6c4SBarry Smith 134f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 135ce94432eSBarry Smith if (dof > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems"); 136ce94432eSBarry Smith if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()"); 137fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid)); 1388b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper)); 139fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid)); 140f4bdf6c4SBarry Smith 14159cb773eSBarry Smith sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0]; 1428b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,(HYPRE_Int *)sw)); 143f4bdf6c4SBarry Smith 144f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 145ce94432eSBarry Smith if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 146ce94432eSBarry Smith if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 147f4bdf6c4SBarry Smith if (dim == 1) { 1484ddd07fcSJed Brown PetscInt offsets[3][1] = {{-1},{0},{1}}; 149f4bdf6c4SBarry Smith ssize = 3; 150fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 151f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1528b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 153f4bdf6c4SBarry Smith } 154f4bdf6c4SBarry Smith } else if (dim == 2) { 1554ddd07fcSJed Brown PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 156f4bdf6c4SBarry Smith ssize = 5; 157fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 158f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1598b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 160f4bdf6c4SBarry Smith } 161f4bdf6c4SBarry Smith } else if (dim == 3) { 1624ddd07fcSJed Brown 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}}; 163f4bdf6c4SBarry Smith ssize = 7; 164fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 165f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1668b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 167f4bdf6c4SBarry Smith } 168f4bdf6c4SBarry Smith } 169f4bdf6c4SBarry Smith 170f4bdf6c4SBarry Smith /* create the HYPRE vector for rhs and solution */ 171fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb)); 172fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx)); 173fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb)); 174fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx)); 175fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb)); 176fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx)); 177f4bdf6c4SBarry Smith 178f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 179fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat)); 180fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid)); 181fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil)); 182f4bdf6c4SBarry Smith if (ex->needsinitialization) { 183fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat)); 184f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 185f4bdf6c4SBarry Smith } 186f4bdf6c4SBarry Smith 187f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 188f4bdf6c4SBarry Smith ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 189f4bdf6c4SBarry Smith ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 190f4bdf6c4SBarry Smith ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 191f4bdf6c4SBarry Smith ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 192f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 193f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 19459cb773eSBarry Smith mat->preallocated = PETSC_TRUE; 195f4bdf6c4SBarry Smith 196f4bdf6c4SBarry Smith if (dim == 3) { 197f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 198f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 199f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 2008865f1eaSKarl Rupp 20159cb773eSBarry Smith /* ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr); */ 202ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 203f4bdf6c4SBarry Smith 204f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 2050298fd71SBarry Smith ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 206565245c5SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 207565245c5SBarry Smith ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 208f4bdf6c4SBarry Smith ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr); 209f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 210f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr); 211f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 212f4bdf6c4SBarry Smith PetscFunctionReturn(0); 213f4bdf6c4SBarry Smith } 214f4bdf6c4SBarry Smith 215f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y) 216f4bdf6c4SBarry Smith { 217f4bdf6c4SBarry Smith PetscErrorCode ierr; 218b026d285SBarry Smith const PetscScalar *xx; 219b026d285SBarry Smith PetscScalar *yy; 2204ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 221f4bdf6c4SBarry Smith Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data); 222f4bdf6c4SBarry Smith 223f4bdf6c4SBarry Smith PetscFunctionBegin; 224f4bdf6c4SBarry Smith ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 2258865f1eaSKarl Rupp 226f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 227f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 228f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 229f4bdf6c4SBarry Smith 230f4bdf6c4SBarry Smith /* copy x values over to hypre */ 231fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0)); 232b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 233b026d285SBarry Smith PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,(PetscScalar*)xx)); 234b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 235fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb)); 236fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx)); 237f4bdf6c4SBarry Smith 238f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 239f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 2408b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,yy)); 241f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 242f4bdf6c4SBarry Smith PetscFunctionReturn(0); 243f4bdf6c4SBarry Smith } 244f4bdf6c4SBarry Smith 245f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode) 246f4bdf6c4SBarry Smith { 247f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 248f4bdf6c4SBarry Smith PetscErrorCode ierr; 249f4bdf6c4SBarry Smith 250f4bdf6c4SBarry Smith PetscFunctionBegin; 251fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 252fd3f9acdSBarry Smith /* PetscStackCallStandard(HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */ 253f4bdf6c4SBarry Smith PetscFunctionReturn(0); 254f4bdf6c4SBarry Smith } 255f4bdf6c4SBarry Smith 256f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat) 257f4bdf6c4SBarry Smith { 258f4bdf6c4SBarry Smith PetscFunctionBegin; 259f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 260f4bdf6c4SBarry Smith PetscFunctionReturn(0); 261f4bdf6c4SBarry Smith } 262f4bdf6c4SBarry Smith 263f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPREStruct(Mat mat) 264f4bdf6c4SBarry Smith { 265f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 266f4bdf6c4SBarry Smith PetscErrorCode ierr; 267f4bdf6c4SBarry Smith 268f4bdf6c4SBarry Smith PetscFunctionBegin; 269fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat)); 270fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx)); 271fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb)); 27259cb773eSBarry Smith ierr = PetscObjectDereference((PetscObject)ex->da);CHKERRQ(ierr); 27359cb773eSBarry Smith ierr = MPI_Comm_free(&(ex->hcomm));CHKERRQ(ierr); 27459cb773eSBarry Smith ierr = PetscFree(ex);CHKERRQ(ierr); 275f4bdf6c4SBarry Smith PetscFunctionReturn(0); 276f4bdf6c4SBarry Smith } 277f4bdf6c4SBarry Smith 2788cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B) 279f4bdf6c4SBarry Smith { 280f4bdf6c4SBarry Smith Mat_HYPREStruct *ex; 281f4bdf6c4SBarry Smith PetscErrorCode ierr; 282f4bdf6c4SBarry Smith 283f4bdf6c4SBarry Smith PetscFunctionBegin; 284b00a9115SJed Brown ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 285f4bdf6c4SBarry Smith B->data = (void*)ex; 286f4bdf6c4SBarry Smith B->rmap->bs = 1; 287f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 288f4bdf6c4SBarry Smith 289f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 290f4bdf6c4SBarry Smith 291f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 292f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPREStruct; 293f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPREStruct; 294f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPREStruct; 29559cb773eSBarry Smith B->ops->setup = MatSetUp_HYPREStruct; 296f4bdf6c4SBarry Smith 297f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 298f4bdf6c4SBarry Smith 299ce94432eSBarry Smith ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 300f4bdf6c4SBarry Smith ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr); 301f4bdf6c4SBarry Smith PetscFunctionReturn(0); 302f4bdf6c4SBarry Smith } 303f4bdf6c4SBarry Smith 304f4bdf6c4SBarry Smith /*MC 305f4bdf6c4SBarry Smith MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 306f4bdf6c4SBarry Smith based on the hypre HYPRE_SStructMatrix. 307f4bdf6c4SBarry Smith 308f4bdf6c4SBarry Smith 309f4bdf6c4SBarry Smith Level: intermediate 310f4bdf6c4SBarry Smith 311*95452b02SPatrick Sanan Notes: 312*95452b02SPatrick Sanan Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 313b026d285SBarry Smith grid objects, we restrict the semi-struct objects to consist of only structured-grid components. 314f4bdf6c4SBarry Smith 315f4bdf6c4SBarry Smith 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 316f4bdf6c4SBarry Smith be defined by a DMDA. 317f4bdf6c4SBarry Smith 31859cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 319f4bdf6c4SBarry Smith 320f4bdf6c4SBarry Smith M*/ 321f4bdf6c4SBarry Smith 322f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 323f4bdf6c4SBarry Smith { 324f4bdf6c4SBarry Smith PetscErrorCode ierr; 325f4bdf6c4SBarry Smith PetscInt i,j,stencil,index[3]; 326f4bdf6c4SBarry Smith const PetscScalar *values = y; 327f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 328f4bdf6c4SBarry Smith 3294ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 3304ddd07fcSJed Brown PetscInt ordering; 3314ddd07fcSJed Brown PetscInt grid_rank, to_grid_rank; 3324ddd07fcSJed Brown PetscInt var_type, to_var_type; 3334ddd07fcSJed Brown PetscInt to_var_entry = 0; 3344ddd07fcSJed Brown PetscInt nvars= ex->nvars; 335f4bdf6c4SBarry Smith PetscInt row,*entries; 336f4bdf6c4SBarry Smith 337f4bdf6c4SBarry Smith PetscFunctionBegin; 338785e854fSJed Brown ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 339f4bdf6c4SBarry Smith ordering = ex->dofs_order; /* ordering= 0 nodal ordering 340f4bdf6c4SBarry Smith 1 variable ordering */ 34161710fbeSStefano Zampini /* stencil entries are ordered by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 342f4bdf6c4SBarry Smith if (!ordering) { 343f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 344f4bdf6c4SBarry Smith grid_rank= irow[i]/nvars; 345f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 346f4bdf6c4SBarry Smith 347f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 348f4bdf6c4SBarry Smith to_grid_rank= icol[j]/nvars; 349f4bdf6c4SBarry Smith to_var_type = (icol[j] % nvars); 350f4bdf6c4SBarry Smith 351f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 352f4bdf6c4SBarry Smith entries[j] = to_var_entry; 353f4bdf6c4SBarry Smith 354f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 355f4bdf6c4SBarry Smith if (!stencil) { 356f4bdf6c4SBarry Smith entries[j] += 3; 357f4bdf6c4SBarry Smith } else if (stencil == -1) { 358f4bdf6c4SBarry Smith entries[j] += 2; 359f4bdf6c4SBarry Smith } else if (stencil == 1) { 360f4bdf6c4SBarry Smith entries[j] += 4; 361f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 362f4bdf6c4SBarry Smith entries[j] += 1; 363f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 364f4bdf6c4SBarry Smith entries[j] += 5; 365f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 366f4bdf6c4SBarry Smith entries[j] += 0; 367f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 368f4bdf6c4SBarry Smith entries[j] += 6; 369f4bdf6c4SBarry Smith } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 370f4bdf6c4SBarry Smith } 371f4bdf6c4SBarry Smith 372f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 373f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 374f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 375f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 376f4bdf6c4SBarry Smith 377f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 3788b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 379f4bdf6c4SBarry Smith } else { 3808b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 381f4bdf6c4SBarry Smith } 382f4bdf6c4SBarry Smith values += ncol; 383f4bdf6c4SBarry Smith } 384f4bdf6c4SBarry Smith } else { 385f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 386f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 387f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 388f4bdf6c4SBarry Smith 389f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 390f4bdf6c4SBarry Smith to_var_type = icol[j]/(ex->gnxgnygnz); 391f4bdf6c4SBarry Smith to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz); 392f4bdf6c4SBarry Smith 393f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 394f4bdf6c4SBarry Smith entries[j] = to_var_entry; 395f4bdf6c4SBarry Smith 396f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 397f4bdf6c4SBarry Smith if (!stencil) { 398f4bdf6c4SBarry Smith entries[j] += 3; 399f4bdf6c4SBarry Smith } else if (stencil == -1) { 400f4bdf6c4SBarry Smith entries[j] += 2; 401f4bdf6c4SBarry Smith } else if (stencil == 1) { 402f4bdf6c4SBarry Smith entries[j] += 4; 403f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 404f4bdf6c4SBarry Smith entries[j] += 1; 405f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 406f4bdf6c4SBarry Smith entries[j] += 5; 407f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 408f4bdf6c4SBarry Smith entries[j] += 0; 409f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 410f4bdf6c4SBarry Smith entries[j] += 6; 411f4bdf6c4SBarry Smith } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 412f4bdf6c4SBarry Smith } 413f4bdf6c4SBarry Smith 414f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 415f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 416f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 417f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 418f4bdf6c4SBarry Smith 419f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 4208b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 421f4bdf6c4SBarry Smith } else { 4228b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 423f4bdf6c4SBarry Smith } 424f4bdf6c4SBarry Smith values += ncol; 425f4bdf6c4SBarry Smith } 426f4bdf6c4SBarry Smith } 427f4bdf6c4SBarry Smith ierr = PetscFree(entries);CHKERRQ(ierr); 428f4bdf6c4SBarry Smith PetscFunctionReturn(0); 429f4bdf6c4SBarry Smith } 430f4bdf6c4SBarry Smith 431f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 432f4bdf6c4SBarry Smith { 433f4bdf6c4SBarry Smith PetscErrorCode ierr; 434f4bdf6c4SBarry Smith PetscInt i,index[3]; 435f4bdf6c4SBarry Smith PetscScalar **values; 436f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 437f4bdf6c4SBarry Smith 4384ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 4394ddd07fcSJed Brown PetscInt ordering = ex->dofs_order; 4404ddd07fcSJed Brown PetscInt grid_rank; 4414ddd07fcSJed Brown PetscInt var_type; 4424ddd07fcSJed Brown PetscInt nvars= ex->nvars; 443f4bdf6c4SBarry Smith PetscInt row,*entries; 444f4bdf6c4SBarry Smith 445f4bdf6c4SBarry Smith PetscFunctionBegin; 446ce94432eSBarry Smith if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 447785e854fSJed Brown ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 448f4bdf6c4SBarry Smith 449785e854fSJed Brown ierr = PetscMalloc1(nvars,&values);CHKERRQ(ierr); 450785e854fSJed Brown ierr = PetscMalloc1(7*nvars*nvars,&values[0]);CHKERRQ(ierr); 451f4bdf6c4SBarry Smith for (i=1; i<nvars; i++) { 452f4bdf6c4SBarry Smith values[i] = values[i-1] + nvars*7; 453f4bdf6c4SBarry Smith } 454f4bdf6c4SBarry Smith 455f4bdf6c4SBarry Smith for (i=0; i< nvars; i++) { 456f4bdf6c4SBarry Smith ierr = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr); 457f4bdf6c4SBarry Smith *(values[i]+3) = d; 458f4bdf6c4SBarry Smith } 459f4bdf6c4SBarry Smith 4608865f1eaSKarl Rupp for (i= 0; i< nvars*7; i++) entries[i] = i; 461f4bdf6c4SBarry Smith 462f4bdf6c4SBarry Smith if (!ordering) { 463f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 464f4bdf6c4SBarry Smith grid_rank = irow[i] / nvars; 465f4bdf6c4SBarry Smith var_type =(irow[i] % nvars); 466f4bdf6c4SBarry Smith 467f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 468f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 469f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 470f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 4718b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 472f4bdf6c4SBarry Smith } 473f4bdf6c4SBarry Smith } else { 474f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 475f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 476f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 477f4bdf6c4SBarry Smith 478f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 479f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 480f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 481f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 4828b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 483f4bdf6c4SBarry Smith } 484f4bdf6c4SBarry Smith } 485fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 486f4bdf6c4SBarry Smith ierr = PetscFree(values[0]);CHKERRQ(ierr); 487f4bdf6c4SBarry Smith ierr = PetscFree(values);CHKERRQ(ierr); 488f4bdf6c4SBarry Smith ierr = PetscFree(entries);CHKERRQ(ierr); 489f4bdf6c4SBarry Smith PetscFunctionReturn(0); 490f4bdf6c4SBarry Smith } 491f4bdf6c4SBarry Smith 492f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 493f4bdf6c4SBarry Smith { 494f4bdf6c4SBarry Smith PetscErrorCode ierr; 495f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 4964ddd07fcSJed Brown PetscInt nvars= ex->nvars; 4974ddd07fcSJed Brown PetscInt size; 4984ddd07fcSJed Brown PetscInt part= 0; /* only one part */ 499f4bdf6c4SBarry Smith 500f4bdf6c4SBarry Smith PetscFunctionBegin; 501f4bdf6c4SBarry Smith 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); 502f4bdf6c4SBarry Smith { 5034ddd07fcSJed Brown PetscInt i,*entries,iupper[3],ilower[3]; 504f4bdf6c4SBarry Smith PetscScalar *values; 5054ddd07fcSJed Brown 506f4bdf6c4SBarry Smith 507f4bdf6c4SBarry Smith for (i= 0; i< 3; i++) { 508f4bdf6c4SBarry Smith ilower[i]= ex->hbox.imin[i]; 509f4bdf6c4SBarry Smith iupper[i]= ex->hbox.imax[i]; 510f4bdf6c4SBarry Smith } 511f4bdf6c4SBarry Smith 512dcca6d9dSJed Brown ierr = PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);CHKERRQ(ierr); 5138865f1eaSKarl Rupp for (i= 0; i< nvars*7; i++) entries[i]= i; 514f4bdf6c4SBarry Smith ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr); 515f4bdf6c4SBarry Smith 516f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 5178b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,nvars*7,(HYPRE_Int *)entries,values)); 518f4bdf6c4SBarry Smith } 519f4bdf6c4SBarry Smith ierr = PetscFree2(entries,values);CHKERRQ(ierr); 520f4bdf6c4SBarry Smith } 521fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 522f4bdf6c4SBarry Smith PetscFunctionReturn(0); 523f4bdf6c4SBarry Smith } 524f4bdf6c4SBarry Smith 525f4bdf6c4SBarry Smith 52659cb773eSBarry Smith static PetscErrorCode MatSetUp_HYPRESStruct(Mat mat) 527f4bdf6c4SBarry Smith { 528f4bdf6c4SBarry Smith PetscErrorCode ierr; 529f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 530f4bdf6c4SBarry Smith PetscInt dim,dof,sw[3],nx,ny,nz; 5314ddd07fcSJed Brown PetscInt ilower[3],iupper[3],ssize,i; 532bff4a2f0SMatthew G. Knepley DMBoundaryType px,py,pz; 533f4bdf6c4SBarry Smith DMDAStencilType st; 5344ddd07fcSJed Brown PetscInt nparts= 1; /* assuming only one part */ 5354ddd07fcSJed Brown PetscInt part = 0; 536565245c5SBarry Smith ISLocalToGlobalMapping ltog; 53759cb773eSBarry Smith DM da; 538b026d285SBarry Smith 539f4bdf6c4SBarry Smith PetscFunctionBegin; 54059cb773eSBarry Smith ierr = MatGetDM(mat,(DM*)&da);CHKERRQ(ierr); 541f4bdf6c4SBarry Smith ex->da = da; 542f4bdf6c4SBarry Smith ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 543f4bdf6c4SBarry Smith 5447ab44359SJed Brown ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 545f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 546f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 547f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 548f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 549f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 550f4bdf6c4SBarry Smith ex->hbox.imin[0] = ilower[0]; 551f4bdf6c4SBarry Smith ex->hbox.imin[1] = ilower[1]; 552f4bdf6c4SBarry Smith ex->hbox.imin[2] = ilower[2]; 553f4bdf6c4SBarry Smith ex->hbox.imax[0] = iupper[0]; 554f4bdf6c4SBarry Smith ex->hbox.imax[1] = iupper[1]; 555f4bdf6c4SBarry Smith ex->hbox.imax[2] = iupper[2]; 556f4bdf6c4SBarry Smith 557f4bdf6c4SBarry Smith ex->dofs_order = 0; 558f4bdf6c4SBarry Smith 559f4bdf6c4SBarry Smith /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */ 560f4bdf6c4SBarry Smith ex->nvars= dof; 561f4bdf6c4SBarry Smith 562f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 563ce94432eSBarry Smith if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 564fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid)); 565fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax)); 566f4bdf6c4SBarry Smith { 567f4bdf6c4SBarry Smith HYPRE_SStructVariable *vartypes; 568785e854fSJed Brown ierr = PetscMalloc1(ex->nvars,&vartypes);CHKERRQ(ierr); 5698865f1eaSKarl Rupp for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL; 570fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes)); 571f4bdf6c4SBarry Smith ierr = PetscFree(vartypes);CHKERRQ(ierr); 572f4bdf6c4SBarry Smith } 573fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid)); 574f4bdf6c4SBarry Smith 575f4bdf6c4SBarry Smith sw[1] = sw[0]; 576f4bdf6c4SBarry Smith sw[2] = sw[1]; 577fd3f9acdSBarry Smith /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */ 578f4bdf6c4SBarry Smith 579f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 580ce94432eSBarry Smith if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 581ce94432eSBarry Smith if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 582f4bdf6c4SBarry Smith 583f4bdf6c4SBarry Smith if (dim == 1) { 5844ddd07fcSJed Brown PetscInt offsets[3][1] = {{-1},{0},{1}}; 5854ddd07fcSJed Brown PetscInt j, cnt; 586f4bdf6c4SBarry Smith 587f4bdf6c4SBarry Smith ssize = 3*(ex->nvars); 588fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 589f4bdf6c4SBarry Smith cnt= 0; 590f4bdf6c4SBarry Smith for (i = 0; i < (ex->nvars); i++) { 591f4bdf6c4SBarry Smith for (j = 0; j < 3; j++) { 5928b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 593f4bdf6c4SBarry Smith cnt++; 594f4bdf6c4SBarry Smith } 595f4bdf6c4SBarry Smith } 596f4bdf6c4SBarry Smith } else if (dim == 2) { 5974ddd07fcSJed Brown PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 5984ddd07fcSJed Brown PetscInt j, cnt; 599f4bdf6c4SBarry Smith 600f4bdf6c4SBarry Smith ssize = 5*(ex->nvars); 601fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 602f4bdf6c4SBarry Smith cnt= 0; 603f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 604f4bdf6c4SBarry Smith for (j= 0; j< 5; j++) { 6058b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 606f4bdf6c4SBarry Smith cnt++; 607f4bdf6c4SBarry Smith } 608f4bdf6c4SBarry Smith } 609f4bdf6c4SBarry Smith } else if (dim == 3) { 6104ddd07fcSJed Brown 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}}; 6114ddd07fcSJed Brown PetscInt j, cnt; 612f4bdf6c4SBarry Smith 613f4bdf6c4SBarry Smith ssize = 7*(ex->nvars); 614fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 615f4bdf6c4SBarry Smith cnt= 0; 616f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 617f4bdf6c4SBarry Smith for (j= 0; j< 7; j++) { 6188b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 619f4bdf6c4SBarry Smith cnt++; 620f4bdf6c4SBarry Smith } 621f4bdf6c4SBarry Smith } 622f4bdf6c4SBarry Smith } 623f4bdf6c4SBarry Smith 624f4bdf6c4SBarry Smith /* create the HYPRE graph */ 625fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph))); 626f4bdf6c4SBarry Smith 627f4bdf6c4SBarry Smith /* set the stencil graph. Note that each variable has the same graph. This means that each 628f4bdf6c4SBarry Smith variable couples to all the other variable and with the same stencil pattern. */ 629f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 630fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil)); 631f4bdf6c4SBarry Smith } 632fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph)); 633f4bdf6c4SBarry Smith 634f4bdf6c4SBarry Smith /* create the HYPRE sstruct vectors for rhs and solution */ 635fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b)); 636fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x)); 637fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b)); 638fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x)); 639fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b)); 640fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x)); 641f4bdf6c4SBarry Smith 642f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 643fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat)); 644fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid)); 645fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil)); 646f4bdf6c4SBarry Smith if (ex->needsinitialization) { 647fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat)); 648f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 649f4bdf6c4SBarry Smith } 650f4bdf6c4SBarry Smith 651f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 652f4bdf6c4SBarry Smith ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 653f4bdf6c4SBarry Smith ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 65461710fbeSStefano Zampini ierr = PetscLayoutSetBlockSize(mat->rmap,dof);CHKERRQ(ierr); 65561710fbeSStefano Zampini ierr = PetscLayoutSetBlockSize(mat->cmap,dof);CHKERRQ(ierr); 656f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 657f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 65861710fbeSStefano Zampini mat->preallocated = PETSC_TRUE; 659f4bdf6c4SBarry Smith 660f4bdf6c4SBarry Smith if (dim == 3) { 661f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 662f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 663f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 6648865f1eaSKarl Rupp 66561710fbeSStefano Zampini /* ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr); */ 666ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 667f4bdf6c4SBarry Smith 668f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 6690298fd71SBarry Smith ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 670565245c5SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 671565245c5SBarry Smith ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 672f4bdf6c4SBarry Smith ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);CHKERRQ(ierr); 6738865f1eaSKarl Rupp 674f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 675f4bdf6c4SBarry Smith ex->gnxgnygnz *= ex->gnxgny; 6768865f1eaSKarl Rupp 677f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);CHKERRQ(ierr); 6788865f1eaSKarl Rupp 679f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 680f4bdf6c4SBarry Smith ex->nxnynz = ex->nz*ex->nxny; 681f4bdf6c4SBarry Smith PetscFunctionReturn(0); 682f4bdf6c4SBarry Smith } 683f4bdf6c4SBarry Smith 684f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y) 685f4bdf6c4SBarry Smith { 686f4bdf6c4SBarry Smith PetscErrorCode ierr; 687b026d285SBarry Smith const PetscScalar *xx; 688b026d285SBarry Smith PetscScalar *yy; 6894ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 690f4bdf6c4SBarry Smith Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(A->data); 6914ddd07fcSJed Brown PetscInt ordering= mx->dofs_order; 6924ddd07fcSJed Brown PetscInt nvars = mx->nvars; 6934ddd07fcSJed Brown PetscInt part = 0; 6944ddd07fcSJed Brown PetscInt size; 6954ddd07fcSJed Brown PetscInt i; 696f4bdf6c4SBarry Smith 697f4bdf6c4SBarry Smith PetscFunctionBegin; 698f4bdf6c4SBarry Smith ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 699f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 700f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 701f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 702f4bdf6c4SBarry Smith 703f4bdf6c4SBarry Smith size= 1; 7048865f1eaSKarl Rupp for (i = 0; i < 3; i++) size *= (iupper[i]-ilower[i]+1); 705f4bdf6c4SBarry Smith 706f4bdf6c4SBarry Smith /* copy x values over to hypre for variable ordering */ 707f4bdf6c4SBarry Smith if (ordering) { 708fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 709b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 710f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 711b026d285SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,(PetscScalar*)xx+(size*i))); 712f4bdf6c4SBarry Smith } 713b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 714fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b)); 715fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 716f4bdf6c4SBarry Smith 717f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 718f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 719f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7208b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,yy+(size*i))); 721f4bdf6c4SBarry Smith } 722f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 723f4bdf6c4SBarry Smith } else { /* nodal ordering must be mapped to variable ordering for sys_pfmg */ 724f4bdf6c4SBarry Smith PetscScalar *z; 7254ddd07fcSJed Brown PetscInt j, k; 726f4bdf6c4SBarry Smith 727785e854fSJed Brown ierr = PetscMalloc1(nvars*size,&z);CHKERRQ(ierr); 728fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 729b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 730f4bdf6c4SBarry Smith 731f4bdf6c4SBarry Smith /* transform nodal to hypre's variable ordering for sys_pfmg */ 732f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 733f4bdf6c4SBarry Smith k= i*nvars; 7348865f1eaSKarl Rupp for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j]; 735f4bdf6c4SBarry Smith } 736f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7378b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,z+(size*i))); 738f4bdf6c4SBarry Smith } 739b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 740fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b)); 741fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 742f4bdf6c4SBarry Smith 743f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 744f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 745f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7468b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,z+(size*i))); 747f4bdf6c4SBarry Smith } 748f4bdf6c4SBarry Smith /* transform hypre's variable ordering for sys_pfmg to nodal ordering */ 749f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 750f4bdf6c4SBarry Smith k= i*nvars; 7518865f1eaSKarl Rupp for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i]; 752f4bdf6c4SBarry Smith } 753f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 754f4bdf6c4SBarry Smith ierr = PetscFree(z);CHKERRQ(ierr); 755f4bdf6c4SBarry Smith } 756f4bdf6c4SBarry Smith PetscFunctionReturn(0); 757f4bdf6c4SBarry Smith } 758f4bdf6c4SBarry Smith 759f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode) 760f4bdf6c4SBarry Smith { 761f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 762f4bdf6c4SBarry Smith PetscErrorCode ierr; 763f4bdf6c4SBarry Smith 764f4bdf6c4SBarry Smith PetscFunctionBegin; 765fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 766f4bdf6c4SBarry Smith PetscFunctionReturn(0); 767f4bdf6c4SBarry Smith } 768f4bdf6c4SBarry Smith 769f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat) 770f4bdf6c4SBarry Smith { 771f4bdf6c4SBarry Smith PetscFunctionBegin; 772f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 773f4bdf6c4SBarry Smith PetscFunctionReturn(0); 774f4bdf6c4SBarry Smith } 775f4bdf6c4SBarry Smith 776f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPRESStruct(Mat mat) 777f4bdf6c4SBarry Smith { 778f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 779f4bdf6c4SBarry Smith PetscErrorCode ierr; 780d94fc0b6SBarry Smith ISLocalToGlobalMapping ltog; 781f4bdf6c4SBarry Smith 782f4bdf6c4SBarry Smith PetscFunctionBegin; 783d94fc0b6SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 784d94fc0b6SBarry Smith ierr = ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 785fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphDestroy,(ex->ss_graph)); 786fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixDestroy,(ex->ss_mat)); 787fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_x)); 788fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_b)); 78959cb773eSBarry Smith ierr = PetscObjectDereference((PetscObject)ex->da);CHKERRQ(ierr); 79059cb773eSBarry Smith ierr = MPI_Comm_free(&(ex->hcomm));CHKERRQ(ierr); 79159cb773eSBarry Smith ierr = PetscFree(ex);CHKERRQ(ierr); 792f4bdf6c4SBarry Smith PetscFunctionReturn(0); 793f4bdf6c4SBarry Smith } 794f4bdf6c4SBarry Smith 7958cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B) 796f4bdf6c4SBarry Smith { 797f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex; 798f4bdf6c4SBarry Smith PetscErrorCode ierr; 799f4bdf6c4SBarry Smith 800f4bdf6c4SBarry Smith PetscFunctionBegin; 801b00a9115SJed Brown ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 802f4bdf6c4SBarry Smith B->data = (void*)ex; 803f4bdf6c4SBarry Smith B->rmap->bs = 1; 804f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 805f4bdf6c4SBarry Smith 806f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 807f4bdf6c4SBarry Smith 808f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 809f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPRESStruct; 810f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 811f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPRESStruct; 81259cb773eSBarry Smith B->ops->setup = MatSetUp_HYPRESStruct; 813f4bdf6c4SBarry Smith 814f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 815f4bdf6c4SBarry Smith 816ce94432eSBarry Smith ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 817f4bdf6c4SBarry Smith ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr); 818f4bdf6c4SBarry Smith PetscFunctionReturn(0); 819f4bdf6c4SBarry Smith } 820f4bdf6c4SBarry Smith 821f4bdf6c4SBarry Smith 822f4bdf6c4SBarry Smith 823