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 18f4bdf6c4SBarry Smith Notes: Unlike the more general support for blocks in hypre this allows only one block per process and requires the block 19f4bdf6c4SBarry Smith be defined by a DMDA. 20f4bdf6c4SBarry Smith 2159cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 22f4bdf6c4SBarry Smith 2359cb773eSBarry Smith .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix() 24f4bdf6c4SBarry Smith M*/ 25f4bdf6c4SBarry Smith 26f4bdf6c4SBarry Smith 27f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 28f4bdf6c4SBarry Smith { 29f4bdf6c4SBarry Smith PetscErrorCode ierr; 30f4bdf6c4SBarry Smith PetscInt i,j,stencil,index[3],row,entries[7]; 31f4bdf6c4SBarry Smith const PetscScalar *values = y; 32f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 33f4bdf6c4SBarry Smith 34f4bdf6c4SBarry Smith PetscFunctionBegin; 3559cb773eSBarry Smith if (PetscUnlikely(ncol > 7)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"ncol %D > 7 too large",ncol); 36f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 37f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 38f4bdf6c4SBarry Smith stencil = icol[j] - irow[i]; 39f4bdf6c4SBarry Smith if (!stencil) { 40f4bdf6c4SBarry Smith entries[j] = 3; 41f4bdf6c4SBarry Smith } else if (stencil == -1) { 42f4bdf6c4SBarry Smith entries[j] = 2; 43f4bdf6c4SBarry Smith } else if (stencil == 1) { 44f4bdf6c4SBarry Smith entries[j] = 4; 45f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 46f4bdf6c4SBarry Smith entries[j] = 1; 47f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 48f4bdf6c4SBarry Smith entries[j] = 5; 49f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 50f4bdf6c4SBarry Smith entries[j] = 0; 51f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 52f4bdf6c4SBarry Smith entries[j] = 6; 53f4bdf6c4SBarry 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); 54f4bdf6c4SBarry Smith } 55f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 56f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 57f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 58f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 59f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 608b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAddToValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 61f4bdf6c4SBarry Smith } else { 628b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 63f4bdf6c4SBarry Smith } 64f4bdf6c4SBarry Smith values += ncol; 65f4bdf6c4SBarry Smith } 66f4bdf6c4SBarry Smith PetscFunctionReturn(0); 67f4bdf6c4SBarry Smith } 68f4bdf6c4SBarry Smith 69f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 70f4bdf6c4SBarry Smith { 71f4bdf6c4SBarry Smith PetscErrorCode ierr; 72f4bdf6c4SBarry Smith PetscInt i,index[3],row,entries[7] = {0,1,2,3,4,5,6}; 73f4bdf6c4SBarry Smith PetscScalar values[7]; 74f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 75f4bdf6c4SBarry Smith 76f4bdf6c4SBarry Smith PetscFunctionBegin; 77ce94432eSBarry Smith if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 78f4bdf6c4SBarry Smith ierr = PetscMemzero(values,7*sizeof(PetscScalar));CHKERRQ(ierr); 79f4bdf6c4SBarry Smith values[3] = d; 80f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 81f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 82f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 83f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 84f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 858b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,7,(HYPRE_Int *)entries,values)); 86f4bdf6c4SBarry Smith } 87fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 88f4bdf6c4SBarry Smith PetscFunctionReturn(0); 89f4bdf6c4SBarry Smith } 90f4bdf6c4SBarry Smith 91f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat) 92f4bdf6c4SBarry Smith { 93f4bdf6c4SBarry Smith PetscErrorCode ierr; 94f4bdf6c4SBarry Smith PetscInt indices[7] = {0,1,2,3,4,5,6}; 95f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 96f4bdf6c4SBarry Smith 97f4bdf6c4SBarry Smith PetscFunctionBegin; 98f4bdf6c4SBarry Smith /* hypre has no public interface to do this */ 998b1f7689SBarry Smith PetscStackCallStandard(hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,(HYPRE_Int *)indices,0,1)); 100fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 101f4bdf6c4SBarry Smith PetscFunctionReturn(0); 102f4bdf6c4SBarry Smith } 103f4bdf6c4SBarry Smith 10459cb773eSBarry Smith static PetscErrorCode MatSetUp_HYPREStruct(Mat mat) 105f4bdf6c4SBarry Smith { 106f4bdf6c4SBarry Smith PetscErrorCode ierr; 107f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 10859cb773eSBarry Smith PetscInt dim,dof,sw[6],nx,ny,nz,ilower[3],iupper[3],ssize,i; 109bff4a2f0SMatthew G. Knepley DMBoundaryType px,py,pz; 110f4bdf6c4SBarry Smith DMDAStencilType st; 111565245c5SBarry Smith ISLocalToGlobalMapping ltog; 11259cb773eSBarry Smith DM da; 113f4bdf6c4SBarry Smith 114f4bdf6c4SBarry Smith PetscFunctionBegin; 11559cb773eSBarry Smith ierr = MatGetDM(mat,(DM*)&da);CHKERRQ(ierr); 116f4bdf6c4SBarry Smith ex->da = da; 117f4bdf6c4SBarry Smith ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 118f4bdf6c4SBarry Smith 1197ab44359SJed Brown ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 120f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 121f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 122f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 123f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 124f4bdf6c4SBarry Smith 125f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 126f4bdf6c4SBarry Smith ex->hbox.imin[0] = ilower[0]; 127f4bdf6c4SBarry Smith ex->hbox.imin[1] = ilower[1]; 128f4bdf6c4SBarry Smith ex->hbox.imin[2] = ilower[2]; 129f4bdf6c4SBarry Smith ex->hbox.imax[0] = iupper[0]; 130f4bdf6c4SBarry Smith ex->hbox.imax[1] = iupper[1]; 131f4bdf6c4SBarry Smith ex->hbox.imax[2] = iupper[2]; 132f4bdf6c4SBarry Smith 133f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 134ce94432eSBarry Smith if (dof > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems"); 135ce94432eSBarry Smith if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()"); 136fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid)); 1378b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper)); 138fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid)); 139f4bdf6c4SBarry Smith 14059cb773eSBarry Smith sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0]; 1418b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,(HYPRE_Int *)sw)); 142f4bdf6c4SBarry Smith 143f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 144ce94432eSBarry Smith if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 145ce94432eSBarry Smith if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 146f4bdf6c4SBarry Smith if (dim == 1) { 1474ddd07fcSJed Brown PetscInt offsets[3][1] = {{-1},{0},{1}}; 148f4bdf6c4SBarry Smith ssize = 3; 149fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 150f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1518b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 152f4bdf6c4SBarry Smith } 153f4bdf6c4SBarry Smith } else if (dim == 2) { 1544ddd07fcSJed Brown PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 155f4bdf6c4SBarry Smith ssize = 5; 156fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 157f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1588b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 159f4bdf6c4SBarry Smith } 160f4bdf6c4SBarry Smith } else if (dim == 3) { 1614ddd07fcSJed 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}}; 162f4bdf6c4SBarry Smith ssize = 7; 163fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 164f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 1658b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 166f4bdf6c4SBarry Smith } 167f4bdf6c4SBarry Smith } 168f4bdf6c4SBarry Smith 169f4bdf6c4SBarry Smith /* create the HYPRE vector for rhs and solution */ 170fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb)); 171fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx)); 172fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb)); 173fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx)); 174fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb)); 175fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx)); 176f4bdf6c4SBarry Smith 177f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 178fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat)); 179fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid)); 180fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil)); 181f4bdf6c4SBarry Smith if (ex->needsinitialization) { 182fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat)); 183f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 184f4bdf6c4SBarry Smith } 185f4bdf6c4SBarry Smith 186f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 187f4bdf6c4SBarry Smith ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 188f4bdf6c4SBarry Smith ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 189f4bdf6c4SBarry Smith ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 190f4bdf6c4SBarry Smith ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 191f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 192f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 19359cb773eSBarry Smith mat->preallocated = PETSC_TRUE; 194f4bdf6c4SBarry Smith 195f4bdf6c4SBarry Smith if (dim == 3) { 196f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 197f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 198f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 1998865f1eaSKarl Rupp 20059cb773eSBarry Smith /* ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr); */ 201ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 202f4bdf6c4SBarry Smith 203f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 2040298fd71SBarry Smith ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 205565245c5SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 206565245c5SBarry Smith ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 207f4bdf6c4SBarry Smith ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr); 208f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 209f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr); 210f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 211f4bdf6c4SBarry Smith PetscFunctionReturn(0); 212f4bdf6c4SBarry Smith } 213f4bdf6c4SBarry Smith 214f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y) 215f4bdf6c4SBarry Smith { 216f4bdf6c4SBarry Smith PetscErrorCode ierr; 217b026d285SBarry Smith const PetscScalar *xx; 218b026d285SBarry Smith PetscScalar *yy; 2194ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 220f4bdf6c4SBarry Smith Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data); 221f4bdf6c4SBarry Smith 222f4bdf6c4SBarry Smith PetscFunctionBegin; 223f4bdf6c4SBarry Smith ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 2248865f1eaSKarl Rupp 225f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 226f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 227f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 228f4bdf6c4SBarry Smith 229f4bdf6c4SBarry Smith /* copy x values over to hypre */ 230fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0)); 231b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 232b026d285SBarry Smith PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,(PetscScalar*)xx)); 233b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 234fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb)); 235fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx)); 236f4bdf6c4SBarry Smith 237f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 238f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 2398b1f7689SBarry Smith PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,yy)); 240f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 241f4bdf6c4SBarry Smith PetscFunctionReturn(0); 242f4bdf6c4SBarry Smith } 243f4bdf6c4SBarry Smith 244f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode) 245f4bdf6c4SBarry Smith { 246f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 247f4bdf6c4SBarry Smith PetscErrorCode ierr; 248f4bdf6c4SBarry Smith 249f4bdf6c4SBarry Smith PetscFunctionBegin; 250fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 251fd3f9acdSBarry Smith /* PetscStackCallStandard(HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */ 252f4bdf6c4SBarry Smith PetscFunctionReturn(0); 253f4bdf6c4SBarry Smith } 254f4bdf6c4SBarry Smith 255f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat) 256f4bdf6c4SBarry Smith { 257f4bdf6c4SBarry Smith PetscFunctionBegin; 258f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 259f4bdf6c4SBarry Smith PetscFunctionReturn(0); 260f4bdf6c4SBarry Smith } 261f4bdf6c4SBarry Smith 262f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPREStruct(Mat mat) 263f4bdf6c4SBarry Smith { 264f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 265f4bdf6c4SBarry Smith PetscErrorCode ierr; 266f4bdf6c4SBarry Smith 267f4bdf6c4SBarry Smith PetscFunctionBegin; 268fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat)); 269fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx)); 270fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb)); 27159cb773eSBarry Smith ierr = PetscObjectDereference((PetscObject)ex->da);CHKERRQ(ierr); 27259cb773eSBarry Smith ierr = MPI_Comm_free(&(ex->hcomm));CHKERRQ(ierr); 27359cb773eSBarry Smith ierr = PetscFree(ex);CHKERRQ(ierr); 274f4bdf6c4SBarry Smith PetscFunctionReturn(0); 275f4bdf6c4SBarry Smith } 276f4bdf6c4SBarry Smith 2778cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B) 278f4bdf6c4SBarry Smith { 279f4bdf6c4SBarry Smith Mat_HYPREStruct *ex; 280f4bdf6c4SBarry Smith PetscErrorCode ierr; 281f4bdf6c4SBarry Smith 282f4bdf6c4SBarry Smith PetscFunctionBegin; 283b00a9115SJed Brown ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 284f4bdf6c4SBarry Smith B->data = (void*)ex; 285f4bdf6c4SBarry Smith B->rmap->bs = 1; 286f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 287f4bdf6c4SBarry Smith 288f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 289f4bdf6c4SBarry Smith 290f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 291f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPREStruct; 292f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPREStruct; 293f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPREStruct; 29459cb773eSBarry Smith B->ops->setup = MatSetUp_HYPREStruct; 295f4bdf6c4SBarry Smith 296f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 297f4bdf6c4SBarry Smith 298ce94432eSBarry Smith ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 299f4bdf6c4SBarry Smith ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr); 300f4bdf6c4SBarry Smith PetscFunctionReturn(0); 301f4bdf6c4SBarry Smith } 302f4bdf6c4SBarry Smith 303f4bdf6c4SBarry Smith /*MC 304f4bdf6c4SBarry Smith MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 305f4bdf6c4SBarry Smith based on the hypre HYPRE_SStructMatrix. 306f4bdf6c4SBarry Smith 307f4bdf6c4SBarry Smith 308f4bdf6c4SBarry Smith Level: intermediate 309f4bdf6c4SBarry Smith 310f4bdf6c4SBarry Smith Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 311b026d285SBarry Smith grid objects, we restrict the semi-struct objects to consist of only structured-grid components. 312f4bdf6c4SBarry Smith 313f4bdf6c4SBarry 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 314f4bdf6c4SBarry Smith be defined by a DMDA. 315f4bdf6c4SBarry Smith 31659cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 317f4bdf6c4SBarry Smith 318f4bdf6c4SBarry Smith M*/ 319f4bdf6c4SBarry Smith 320f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 321f4bdf6c4SBarry Smith { 322f4bdf6c4SBarry Smith PetscErrorCode ierr; 323f4bdf6c4SBarry Smith PetscInt i,j,stencil,index[3]; 324f4bdf6c4SBarry Smith const PetscScalar *values = y; 325f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 326f4bdf6c4SBarry Smith 3274ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 3284ddd07fcSJed Brown PetscInt ordering; 3294ddd07fcSJed Brown PetscInt grid_rank, to_grid_rank; 3304ddd07fcSJed Brown PetscInt var_type, to_var_type; 3314ddd07fcSJed Brown PetscInt to_var_entry = 0; 3324ddd07fcSJed Brown PetscInt nvars= ex->nvars; 333f4bdf6c4SBarry Smith PetscInt row,*entries; 334f4bdf6c4SBarry Smith 335f4bdf6c4SBarry Smith PetscFunctionBegin; 336785e854fSJed Brown ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 337f4bdf6c4SBarry Smith ordering = ex->dofs_order; /* ordering= 0 nodal ordering 338f4bdf6c4SBarry Smith 1 variable ordering */ 33961710fbeSStefano Zampini /* stencil entries are ordered by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 340f4bdf6c4SBarry Smith if (!ordering) { 341f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 342f4bdf6c4SBarry Smith grid_rank= irow[i]/nvars; 343f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 344f4bdf6c4SBarry Smith 345f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 346f4bdf6c4SBarry Smith to_grid_rank= icol[j]/nvars; 347f4bdf6c4SBarry Smith to_var_type = (icol[j] % nvars); 348f4bdf6c4SBarry Smith 349f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 350f4bdf6c4SBarry Smith entries[j] = to_var_entry; 351f4bdf6c4SBarry Smith 352f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 353f4bdf6c4SBarry Smith if (!stencil) { 354f4bdf6c4SBarry Smith entries[j] += 3; 355f4bdf6c4SBarry Smith } else if (stencil == -1) { 356f4bdf6c4SBarry Smith entries[j] += 2; 357f4bdf6c4SBarry Smith } else if (stencil == 1) { 358f4bdf6c4SBarry Smith entries[j] += 4; 359f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 360f4bdf6c4SBarry Smith entries[j] += 1; 361f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 362f4bdf6c4SBarry Smith entries[j] += 5; 363f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 364f4bdf6c4SBarry Smith entries[j] += 0; 365f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 366f4bdf6c4SBarry Smith entries[j] += 6; 367f4bdf6c4SBarry 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); 368f4bdf6c4SBarry Smith } 369f4bdf6c4SBarry Smith 370f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 371f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 372f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 373f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 374f4bdf6c4SBarry Smith 375f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 3768b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 377f4bdf6c4SBarry Smith } else { 3788b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 379f4bdf6c4SBarry Smith } 380f4bdf6c4SBarry Smith values += ncol; 381f4bdf6c4SBarry Smith } 382f4bdf6c4SBarry Smith } else { 383f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 384f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 385f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 386f4bdf6c4SBarry Smith 387f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 388f4bdf6c4SBarry Smith to_var_type = icol[j]/(ex->gnxgnygnz); 389f4bdf6c4SBarry Smith to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz); 390f4bdf6c4SBarry Smith 391f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 392f4bdf6c4SBarry Smith entries[j] = to_var_entry; 393f4bdf6c4SBarry Smith 394f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 395f4bdf6c4SBarry Smith if (!stencil) { 396f4bdf6c4SBarry Smith entries[j] += 3; 397f4bdf6c4SBarry Smith } else if (stencil == -1) { 398f4bdf6c4SBarry Smith entries[j] += 2; 399f4bdf6c4SBarry Smith } else if (stencil == 1) { 400f4bdf6c4SBarry Smith entries[j] += 4; 401f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 402f4bdf6c4SBarry Smith entries[j] += 1; 403f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 404f4bdf6c4SBarry Smith entries[j] += 5; 405f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 406f4bdf6c4SBarry Smith entries[j] += 0; 407f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 408f4bdf6c4SBarry Smith entries[j] += 6; 409f4bdf6c4SBarry 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); 410f4bdf6c4SBarry Smith } 411f4bdf6c4SBarry Smith 412f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 413f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 414f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 415f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 416f4bdf6c4SBarry Smith 417f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 4188b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 419f4bdf6c4SBarry Smith } else { 4208b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 421f4bdf6c4SBarry Smith } 422f4bdf6c4SBarry Smith values += ncol; 423f4bdf6c4SBarry Smith } 424f4bdf6c4SBarry Smith } 425f4bdf6c4SBarry Smith ierr = PetscFree(entries);CHKERRQ(ierr); 426f4bdf6c4SBarry Smith PetscFunctionReturn(0); 427f4bdf6c4SBarry Smith } 428f4bdf6c4SBarry Smith 429f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 430f4bdf6c4SBarry Smith { 431f4bdf6c4SBarry Smith PetscErrorCode ierr; 432f4bdf6c4SBarry Smith PetscInt i,index[3]; 433f4bdf6c4SBarry Smith PetscScalar **values; 434f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 435f4bdf6c4SBarry Smith 4364ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 4374ddd07fcSJed Brown PetscInt ordering = ex->dofs_order; 4384ddd07fcSJed Brown PetscInt grid_rank; 4394ddd07fcSJed Brown PetscInt var_type; 4404ddd07fcSJed Brown PetscInt nvars= ex->nvars; 441f4bdf6c4SBarry Smith PetscInt row,*entries; 442f4bdf6c4SBarry Smith 443f4bdf6c4SBarry Smith PetscFunctionBegin; 444ce94432eSBarry Smith if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 445785e854fSJed Brown ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 446f4bdf6c4SBarry Smith 447785e854fSJed Brown ierr = PetscMalloc1(nvars,&values);CHKERRQ(ierr); 448785e854fSJed Brown ierr = PetscMalloc1(7*nvars*nvars,&values[0]);CHKERRQ(ierr); 449f4bdf6c4SBarry Smith for (i=1; i<nvars; i++) { 450f4bdf6c4SBarry Smith values[i] = values[i-1] + nvars*7; 451f4bdf6c4SBarry Smith } 452f4bdf6c4SBarry Smith 453f4bdf6c4SBarry Smith for (i=0; i< nvars; i++) { 454f4bdf6c4SBarry Smith ierr = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr); 455f4bdf6c4SBarry Smith *(values[i]+3) = d; 456f4bdf6c4SBarry Smith } 457f4bdf6c4SBarry Smith 4588865f1eaSKarl Rupp for (i= 0; i< nvars*7; i++) entries[i] = i; 459f4bdf6c4SBarry Smith 460f4bdf6c4SBarry Smith if (!ordering) { 461f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 462f4bdf6c4SBarry Smith grid_rank = irow[i] / nvars; 463f4bdf6c4SBarry Smith var_type =(irow[i] % nvars); 464f4bdf6c4SBarry Smith 465f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 466f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 467f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 468f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 4698b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 470f4bdf6c4SBarry Smith } 471f4bdf6c4SBarry Smith } else { 472f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 473f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 474f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 475f4bdf6c4SBarry Smith 476f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 477f4bdf6c4SBarry Smith index[0] = ex->xs + (row % ex->nx); 478f4bdf6c4SBarry Smith index[1] = ex->ys + ((row/ex->nx) % ex->ny); 479f4bdf6c4SBarry Smith index[2] = ex->zs + (row/(ex->nxny)); 4808b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 481f4bdf6c4SBarry Smith } 482f4bdf6c4SBarry Smith } 483fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 484f4bdf6c4SBarry Smith ierr = PetscFree(values[0]);CHKERRQ(ierr); 485f4bdf6c4SBarry Smith ierr = PetscFree(values);CHKERRQ(ierr); 486f4bdf6c4SBarry Smith ierr = PetscFree(entries);CHKERRQ(ierr); 487f4bdf6c4SBarry Smith PetscFunctionReturn(0); 488f4bdf6c4SBarry Smith } 489f4bdf6c4SBarry Smith 490f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 491f4bdf6c4SBarry Smith { 492f4bdf6c4SBarry Smith PetscErrorCode ierr; 493f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 4944ddd07fcSJed Brown PetscInt nvars= ex->nvars; 4954ddd07fcSJed Brown PetscInt size; 4964ddd07fcSJed Brown PetscInt part= 0; /* only one part */ 497f4bdf6c4SBarry Smith 498f4bdf6c4SBarry Smith PetscFunctionBegin; 499f4bdf6c4SBarry 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); 500f4bdf6c4SBarry Smith { 5014ddd07fcSJed Brown PetscInt i,*entries,iupper[3],ilower[3]; 502f4bdf6c4SBarry Smith PetscScalar *values; 5034ddd07fcSJed Brown 504f4bdf6c4SBarry Smith 505f4bdf6c4SBarry Smith for (i= 0; i< 3; i++) { 506f4bdf6c4SBarry Smith ilower[i]= ex->hbox.imin[i]; 507f4bdf6c4SBarry Smith iupper[i]= ex->hbox.imax[i]; 508f4bdf6c4SBarry Smith } 509f4bdf6c4SBarry Smith 510dcca6d9dSJed Brown ierr = PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);CHKERRQ(ierr); 5118865f1eaSKarl Rupp for (i= 0; i< nvars*7; i++) entries[i]= i; 512f4bdf6c4SBarry Smith ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr); 513f4bdf6c4SBarry Smith 514f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 5158b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,nvars*7,(HYPRE_Int *)entries,values)); 516f4bdf6c4SBarry Smith } 517f4bdf6c4SBarry Smith ierr = PetscFree2(entries,values);CHKERRQ(ierr); 518f4bdf6c4SBarry Smith } 519fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 520f4bdf6c4SBarry Smith PetscFunctionReturn(0); 521f4bdf6c4SBarry Smith } 522f4bdf6c4SBarry Smith 523f4bdf6c4SBarry Smith 52459cb773eSBarry Smith static PetscErrorCode MatSetUp_HYPRESStruct(Mat mat) 525f4bdf6c4SBarry Smith { 526f4bdf6c4SBarry Smith PetscErrorCode ierr; 527f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 528f4bdf6c4SBarry Smith PetscInt dim,dof,sw[3],nx,ny,nz; 5294ddd07fcSJed Brown PetscInt ilower[3],iupper[3],ssize,i; 530bff4a2f0SMatthew G. Knepley DMBoundaryType px,py,pz; 531f4bdf6c4SBarry Smith DMDAStencilType st; 5324ddd07fcSJed Brown PetscInt nparts= 1; /* assuming only one part */ 5334ddd07fcSJed Brown PetscInt part = 0; 534565245c5SBarry Smith ISLocalToGlobalMapping ltog; 53559cb773eSBarry Smith DM da; 536b026d285SBarry Smith 537f4bdf6c4SBarry Smith PetscFunctionBegin; 53859cb773eSBarry Smith ierr = MatGetDM(mat,(DM*)&da);CHKERRQ(ierr); 539f4bdf6c4SBarry Smith ex->da = da; 540f4bdf6c4SBarry Smith ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 541f4bdf6c4SBarry Smith 5427ab44359SJed Brown ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 543f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 544f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 545f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 546f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 547f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 548f4bdf6c4SBarry Smith ex->hbox.imin[0] = ilower[0]; 549f4bdf6c4SBarry Smith ex->hbox.imin[1] = ilower[1]; 550f4bdf6c4SBarry Smith ex->hbox.imin[2] = ilower[2]; 551f4bdf6c4SBarry Smith ex->hbox.imax[0] = iupper[0]; 552f4bdf6c4SBarry Smith ex->hbox.imax[1] = iupper[1]; 553f4bdf6c4SBarry Smith ex->hbox.imax[2] = iupper[2]; 554f4bdf6c4SBarry Smith 555f4bdf6c4SBarry Smith ex->dofs_order = 0; 556f4bdf6c4SBarry Smith 557f4bdf6c4SBarry Smith /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */ 558f4bdf6c4SBarry Smith ex->nvars= dof; 559f4bdf6c4SBarry Smith 560f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 561ce94432eSBarry Smith if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 562fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid)); 563fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax)); 564f4bdf6c4SBarry Smith { 565f4bdf6c4SBarry Smith HYPRE_SStructVariable *vartypes; 566785e854fSJed Brown ierr = PetscMalloc1(ex->nvars,&vartypes);CHKERRQ(ierr); 5678865f1eaSKarl Rupp for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL; 568fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes)); 569f4bdf6c4SBarry Smith ierr = PetscFree(vartypes);CHKERRQ(ierr); 570f4bdf6c4SBarry Smith } 571fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid)); 572f4bdf6c4SBarry Smith 573f4bdf6c4SBarry Smith sw[1] = sw[0]; 574f4bdf6c4SBarry Smith sw[2] = sw[1]; 575fd3f9acdSBarry Smith /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */ 576f4bdf6c4SBarry Smith 577f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 578ce94432eSBarry Smith if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 579ce94432eSBarry Smith if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 580f4bdf6c4SBarry Smith 581f4bdf6c4SBarry Smith if (dim == 1) { 5824ddd07fcSJed Brown PetscInt offsets[3][1] = {{-1},{0},{1}}; 5834ddd07fcSJed Brown PetscInt j, cnt; 584f4bdf6c4SBarry Smith 585f4bdf6c4SBarry Smith ssize = 3*(ex->nvars); 586fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 587f4bdf6c4SBarry Smith cnt= 0; 588f4bdf6c4SBarry Smith for (i = 0; i < (ex->nvars); i++) { 589f4bdf6c4SBarry Smith for (j = 0; j < 3; j++) { 5908b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 591f4bdf6c4SBarry Smith cnt++; 592f4bdf6c4SBarry Smith } 593f4bdf6c4SBarry Smith } 594f4bdf6c4SBarry Smith } else if (dim == 2) { 5954ddd07fcSJed Brown PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 5964ddd07fcSJed Brown PetscInt j, cnt; 597f4bdf6c4SBarry Smith 598f4bdf6c4SBarry Smith ssize = 5*(ex->nvars); 599fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 600f4bdf6c4SBarry Smith cnt= 0; 601f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 602f4bdf6c4SBarry Smith for (j= 0; j< 5; j++) { 6038b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 604f4bdf6c4SBarry Smith cnt++; 605f4bdf6c4SBarry Smith } 606f4bdf6c4SBarry Smith } 607f4bdf6c4SBarry Smith } else if (dim == 3) { 6084ddd07fcSJed 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}}; 6094ddd07fcSJed Brown PetscInt j, cnt; 610f4bdf6c4SBarry Smith 611f4bdf6c4SBarry Smith ssize = 7*(ex->nvars); 612fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 613f4bdf6c4SBarry Smith cnt= 0; 614f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 615f4bdf6c4SBarry Smith for (j= 0; j< 7; j++) { 6168b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 617f4bdf6c4SBarry Smith cnt++; 618f4bdf6c4SBarry Smith } 619f4bdf6c4SBarry Smith } 620f4bdf6c4SBarry Smith } 621f4bdf6c4SBarry Smith 622f4bdf6c4SBarry Smith /* create the HYPRE graph */ 623fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph))); 624f4bdf6c4SBarry Smith 625f4bdf6c4SBarry Smith /* set the stencil graph. Note that each variable has the same graph. This means that each 626f4bdf6c4SBarry Smith variable couples to all the other variable and with the same stencil pattern. */ 627f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 628fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil)); 629f4bdf6c4SBarry Smith } 630fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph)); 631f4bdf6c4SBarry Smith 632f4bdf6c4SBarry Smith /* create the HYPRE sstruct vectors for rhs and solution */ 633fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b)); 634fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x)); 635fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b)); 636fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x)); 637fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b)); 638fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x)); 639f4bdf6c4SBarry Smith 640f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 641fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat)); 642fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid)); 643fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil)); 644f4bdf6c4SBarry Smith if (ex->needsinitialization) { 645fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat)); 646f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 647f4bdf6c4SBarry Smith } 648f4bdf6c4SBarry Smith 649f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 650f4bdf6c4SBarry Smith ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 651f4bdf6c4SBarry Smith ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 65261710fbeSStefano Zampini ierr = PetscLayoutSetBlockSize(mat->rmap,dof);CHKERRQ(ierr); 65361710fbeSStefano Zampini ierr = PetscLayoutSetBlockSize(mat->cmap,dof);CHKERRQ(ierr); 654f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 655f4bdf6c4SBarry Smith ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 65661710fbeSStefano Zampini mat->preallocated = PETSC_TRUE; 657f4bdf6c4SBarry Smith 658f4bdf6c4SBarry Smith if (dim == 3) { 659f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 660f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 661f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 6628865f1eaSKarl Rupp 66361710fbeSStefano Zampini /* ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr); */ 664ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 665f4bdf6c4SBarry Smith 666f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 6670298fd71SBarry Smith ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 668565245c5SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 669565245c5SBarry Smith ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 670f4bdf6c4SBarry Smith ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);CHKERRQ(ierr); 6718865f1eaSKarl Rupp 672f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 673f4bdf6c4SBarry Smith ex->gnxgnygnz *= ex->gnxgny; 6748865f1eaSKarl Rupp 675f4bdf6c4SBarry Smith ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);CHKERRQ(ierr); 6768865f1eaSKarl Rupp 677f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 678f4bdf6c4SBarry Smith ex->nxnynz = ex->nz*ex->nxny; 679f4bdf6c4SBarry Smith PetscFunctionReturn(0); 680f4bdf6c4SBarry Smith } 681f4bdf6c4SBarry Smith 682f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y) 683f4bdf6c4SBarry Smith { 684f4bdf6c4SBarry Smith PetscErrorCode ierr; 685b026d285SBarry Smith const PetscScalar *xx; 686b026d285SBarry Smith PetscScalar *yy; 6874ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 688f4bdf6c4SBarry Smith Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(A->data); 6894ddd07fcSJed Brown PetscInt ordering= mx->dofs_order; 6904ddd07fcSJed Brown PetscInt nvars = mx->nvars; 6914ddd07fcSJed Brown PetscInt part = 0; 6924ddd07fcSJed Brown PetscInt size; 6934ddd07fcSJed Brown PetscInt i; 694f4bdf6c4SBarry Smith 695f4bdf6c4SBarry Smith PetscFunctionBegin; 696f4bdf6c4SBarry Smith ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 697f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 698f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 699f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 700f4bdf6c4SBarry Smith 701f4bdf6c4SBarry Smith size= 1; 7028865f1eaSKarl Rupp for (i = 0; i < 3; i++) size *= (iupper[i]-ilower[i]+1); 703f4bdf6c4SBarry Smith 704f4bdf6c4SBarry Smith /* copy x values over to hypre for variable ordering */ 705f4bdf6c4SBarry Smith if (ordering) { 706fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 707b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 708f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 709b026d285SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,(PetscScalar*)xx+(size*i))); 710f4bdf6c4SBarry Smith } 711b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 712fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b)); 713fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 714f4bdf6c4SBarry Smith 715f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 716f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 717f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7188b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,yy+(size*i))); 719f4bdf6c4SBarry Smith } 720f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 721f4bdf6c4SBarry Smith } else { /* nodal ordering must be mapped to variable ordering for sys_pfmg */ 722f4bdf6c4SBarry Smith PetscScalar *z; 7234ddd07fcSJed Brown PetscInt j, k; 724f4bdf6c4SBarry Smith 725785e854fSJed Brown ierr = PetscMalloc1(nvars*size,&z);CHKERRQ(ierr); 726fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 727b026d285SBarry Smith ierr = VecGetArrayRead(x,&xx);CHKERRQ(ierr); 728f4bdf6c4SBarry Smith 729f4bdf6c4SBarry Smith /* transform nodal to hypre's variable ordering for sys_pfmg */ 730f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 731f4bdf6c4SBarry Smith k= i*nvars; 7328865f1eaSKarl Rupp for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j]; 733f4bdf6c4SBarry Smith } 734f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7358b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,z+(size*i))); 736f4bdf6c4SBarry Smith } 737b026d285SBarry Smith ierr = VecRestoreArrayRead(x,&xx);CHKERRQ(ierr); 738fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b)); 739fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 740f4bdf6c4SBarry Smith 741f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 742f4bdf6c4SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 743f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 7448b1f7689SBarry Smith PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,z+(size*i))); 745f4bdf6c4SBarry Smith } 746f4bdf6c4SBarry Smith /* transform hypre's variable ordering for sys_pfmg to nodal ordering */ 747f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 748f4bdf6c4SBarry Smith k= i*nvars; 7498865f1eaSKarl Rupp for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i]; 750f4bdf6c4SBarry Smith } 751f4bdf6c4SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 752f4bdf6c4SBarry Smith ierr = PetscFree(z);CHKERRQ(ierr); 753f4bdf6c4SBarry Smith } 754f4bdf6c4SBarry Smith PetscFunctionReturn(0); 755f4bdf6c4SBarry Smith } 756f4bdf6c4SBarry Smith 757f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode) 758f4bdf6c4SBarry Smith { 759f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 760f4bdf6c4SBarry Smith PetscErrorCode ierr; 761f4bdf6c4SBarry Smith 762f4bdf6c4SBarry Smith PetscFunctionBegin; 763fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 764f4bdf6c4SBarry Smith PetscFunctionReturn(0); 765f4bdf6c4SBarry Smith } 766f4bdf6c4SBarry Smith 767f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat) 768f4bdf6c4SBarry Smith { 769f4bdf6c4SBarry Smith PetscFunctionBegin; 770f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 771f4bdf6c4SBarry Smith PetscFunctionReturn(0); 772f4bdf6c4SBarry Smith } 773f4bdf6c4SBarry Smith 774f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPRESStruct(Mat mat) 775f4bdf6c4SBarry Smith { 776f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 777f4bdf6c4SBarry Smith PetscErrorCode ierr; 778*d94fc0b6SBarry Smith ISLocalToGlobalMapping ltog; 779f4bdf6c4SBarry Smith 780f4bdf6c4SBarry Smith PetscFunctionBegin; 781*d94fc0b6SBarry Smith ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 782*d94fc0b6SBarry Smith ierr = ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 783fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructGraphDestroy,(ex->ss_graph)); 784fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructMatrixDestroy,(ex->ss_mat)); 785fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_x)); 786fd3f9acdSBarry Smith PetscStackCallStandard(HYPRE_SStructVectorDestroy,(ex->ss_b)); 78759cb773eSBarry Smith ierr = PetscObjectDereference((PetscObject)ex->da);CHKERRQ(ierr); 78859cb773eSBarry Smith ierr = MPI_Comm_free(&(ex->hcomm));CHKERRQ(ierr); 78959cb773eSBarry Smith ierr = PetscFree(ex);CHKERRQ(ierr); 790f4bdf6c4SBarry Smith PetscFunctionReturn(0); 791f4bdf6c4SBarry Smith } 792f4bdf6c4SBarry Smith 7938cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B) 794f4bdf6c4SBarry Smith { 795f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex; 796f4bdf6c4SBarry Smith PetscErrorCode ierr; 797f4bdf6c4SBarry Smith 798f4bdf6c4SBarry Smith PetscFunctionBegin; 799b00a9115SJed Brown ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 800f4bdf6c4SBarry Smith B->data = (void*)ex; 801f4bdf6c4SBarry Smith B->rmap->bs = 1; 802f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 803f4bdf6c4SBarry Smith 804f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 805f4bdf6c4SBarry Smith 806f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 807f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPRESStruct; 808f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 809f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPRESStruct; 81059cb773eSBarry Smith B->ops->setup = MatSetUp_HYPRESStruct; 811f4bdf6c4SBarry Smith 812f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 813f4bdf6c4SBarry Smith 814ce94432eSBarry Smith ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 815f4bdf6c4SBarry Smith ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr); 816f4bdf6c4SBarry Smith PetscFunctionReturn(0); 817f4bdf6c4SBarry Smith } 818f4bdf6c4SBarry Smith 819f4bdf6c4SBarry Smith 820f4bdf6c4SBarry Smith 821