1f4bdf6c4SBarry Smith 2f4bdf6c4SBarry Smith /* 3f4bdf6c4SBarry Smith Creates hypre ijmatrix from PETSc matrix 4f4bdf6c4SBarry Smith */ 5c6db04a5SJed Brown #include <petscsys.h> 639accc25SStefano Zampini #include <petsc/private/petschypre.h> 7af0996ceSBarry Smith #include <petsc/private/matimpl.h> 8c6db04a5SJed Brown #include <petscdmda.h> /*I "petscdmda.h" I*/ 9c6db04a5SJed Brown #include <../src/dm/impls/da/hypre/mhyp.h> 10f4bdf6c4SBarry Smith 11f4bdf6c4SBarry Smith /* -----------------------------------------------------------------------------------------------------------------*/ 12f4bdf6c4SBarry Smith 13f4bdf6c4SBarry Smith /*MC 14f4bdf6c4SBarry Smith MATHYPRESTRUCT - MATHYPRESTRUCT = "hyprestruct" - A matrix type to be used for parallel sparse matrices 15f4bdf6c4SBarry Smith based on the hypre HYPRE_StructMatrix. 16f4bdf6c4SBarry Smith 17f4bdf6c4SBarry Smith Level: intermediate 18f4bdf6c4SBarry Smith 1995452b02SPatrick Sanan Notes: 2095452b02SPatrick Sanan Unlike the more general support for blocks in hypre this allows only one block per process and requires the block 21f4bdf6c4SBarry Smith be defined by a DMDA. 22f4bdf6c4SBarry Smith 2359cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 24f4bdf6c4SBarry Smith 25db781477SPatrick Sanan .seealso: `MatCreate()`, `PCPFMG`, `MatSetDM()`, `DMCreateMatrix()` 26f4bdf6c4SBarry Smith M*/ 27f4bdf6c4SBarry Smith 28*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetValuesLocal_HYPREStruct_3d(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv) 29*d71ae5a4SJacob Faibussowitsch { 3076a007c6Sftrigaux HYPRE_Int index[3], entries[9]; 312cf14000SStefano Zampini PetscInt i, j, stencil, row; 3239accc25SStefano Zampini HYPRE_Complex *values = (HYPRE_Complex *)y; 33f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 34f4bdf6c4SBarry Smith 35f4bdf6c4SBarry Smith PetscFunctionBegin; 3676a007c6Sftrigaux PetscCheck(ncol <= 9, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncol %" PetscInt_FMT " > 9 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; 5463a3b9bcSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row %" PetscInt_FMT " local column %" PetscInt_FMT " have bad stencil %" PetscInt_FMT, irow[i], icol[j], stencil); 55f4bdf6c4SBarry Smith } 56f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 572cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 582cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 592cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 60792fecdfSBarry Smith if (addv == ADD_VALUES) PetscCallExternal(HYPRE_StructMatrixAddToValues, ex->hmat, index, ncol, entries, values); 61792fecdfSBarry Smith else PetscCallExternal(HYPRE_StructMatrixSetValues, ex->hmat, index, ncol, entries, values); 62f4bdf6c4SBarry Smith values += ncol; 63f4bdf6c4SBarry Smith } 64f4bdf6c4SBarry Smith PetscFunctionReturn(0); 65f4bdf6c4SBarry Smith } 66f4bdf6c4SBarry Smith 67*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroRowsLocal_HYPREStruct_3d(Mat mat, PetscInt nrow, const PetscInt irow[], PetscScalar d, Vec x, Vec b) 68*d71ae5a4SJacob Faibussowitsch { 692cf14000SStefano Zampini HYPRE_Int index[3], entries[7] = {0, 1, 2, 3, 4, 5, 6}; 702cf14000SStefano Zampini PetscInt row, i; 7139accc25SStefano Zampini HYPRE_Complex values[7]; 72f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 73f4bdf6c4SBarry Smith 74f4bdf6c4SBarry Smith PetscFunctionBegin; 7508401ef6SPierre Jolivet PetscCheck(!x || !b, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "No support"); 769566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values, 7)); 779566063dSJacob Faibussowitsch PetscCall(PetscHYPREScalarCast(d, &values[3])); 78f4bdf6c4SBarry Smith for (i = 0; i < nrow; i++) { 79f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 802cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 812cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 822cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 83792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixSetValues, ex->hmat, index, 7, entries, values); 84f4bdf6c4SBarry Smith } 85792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixAssemble, ex->hmat); 86f4bdf6c4SBarry Smith PetscFunctionReturn(0); 87f4bdf6c4SBarry Smith } 88f4bdf6c4SBarry Smith 89*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat) 90*d71ae5a4SJacob Faibussowitsch { 912cf14000SStefano Zampini HYPRE_Int indices[7] = {0, 1, 2, 3, 4, 5, 6}; 92f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 93f4bdf6c4SBarry Smith 94f4bdf6c4SBarry Smith PetscFunctionBegin; 95f4bdf6c4SBarry Smith /* hypre has no public interface to do this */ 96792fecdfSBarry Smith PetscCallExternal(hypre_StructMatrixClearBoxValues, ex->hmat, &ex->hbox, 7, indices, 0, 1); 97792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixAssemble, ex->hmat); 98f4bdf6c4SBarry Smith PetscFunctionReturn(0); 99f4bdf6c4SBarry Smith } 100f4bdf6c4SBarry Smith 101*d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_HYPREStruct(Mat mat) 102*d71ae5a4SJacob Faibussowitsch { 103f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 1042cf14000SStefano Zampini HYPRE_Int sw[6]; 105e33d7e95Sftrigaux HYPRE_Int hlower[3], hupper[3], period[3] = {0, 0, 0}; 106e33d7e95Sftrigaux PetscInt dim, dof, psw, Nx, Ny, Nz, nx, ny, nz, ilower[3], iupper[3], ssize, i; 107bff4a2f0SMatthew G. Knepley DMBoundaryType px, py, pz; 108f4bdf6c4SBarry Smith DMDAStencilType st; 109565245c5SBarry Smith ISLocalToGlobalMapping ltog; 11059cb773eSBarry Smith DM da; 111f4bdf6c4SBarry Smith 112f4bdf6c4SBarry Smith PetscFunctionBegin; 1139566063dSJacob Faibussowitsch PetscCall(MatGetDM(mat, (DM *)&da)); 114f4bdf6c4SBarry Smith ex->da = da; 1159566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)da)); 116f4bdf6c4SBarry Smith 117e33d7e95Sftrigaux PetscCall(DMDAGetInfo(ex->da, &dim, &Nx, &Ny, &Nz, 0, 0, 0, &dof, &psw, &px, &py, &pz, &st)); 1189566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da, &ilower[0], &ilower[1], &ilower[2], &iupper[0], &iupper[1], &iupper[2])); 1192cf14000SStefano Zampini 1202cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 121f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 122f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 123f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 1242cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 1252cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 1262cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 1272cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 1282cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 1292cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 130f4bdf6c4SBarry Smith 131f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 1322cf14000SStefano Zampini ex->hbox.imin[0] = hlower[0]; 1332cf14000SStefano Zampini ex->hbox.imin[1] = hlower[1]; 1342cf14000SStefano Zampini ex->hbox.imin[2] = hlower[2]; 1352cf14000SStefano Zampini ex->hbox.imax[0] = hupper[0]; 1362cf14000SStefano Zampini ex->hbox.imax[1] = hupper[1]; 1372cf14000SStefano Zampini ex->hbox.imax[2] = hupper[2]; 138f4bdf6c4SBarry Smith 139f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 14008401ef6SPierre Jolivet PetscCheck(dof <= 1, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Currently only support for scalar problems"); 141e33d7e95Sftrigaux if (px || py || pz) { 142e33d7e95Sftrigaux if (px == DM_BOUNDARY_PERIODIC) period[0] = (HYPRE_Int)Nx; 143e33d7e95Sftrigaux if (py == DM_BOUNDARY_PERIODIC) period[1] = (HYPRE_Int)Ny; 144e33d7e95Sftrigaux if (pz == DM_BOUNDARY_PERIODIC) period[2] = (HYPRE_Int)Nz; 145e33d7e95Sftrigaux } 146792fecdfSBarry Smith PetscCallExternal(HYPRE_StructGridCreate, ex->hcomm, dim, &ex->hgrid); 147792fecdfSBarry Smith PetscCallExternal(HYPRE_StructGridSetExtents, ex->hgrid, hlower, hupper); 148e33d7e95Sftrigaux PetscCallExternal(HYPRE_StructGridSetPeriodic, ex->hgrid, period); 149792fecdfSBarry Smith PetscCallExternal(HYPRE_StructGridAssemble, ex->hgrid); 150f4bdf6c4SBarry Smith 1512cf14000SStefano Zampini sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0] = psw; 152792fecdfSBarry Smith PetscCallExternal(HYPRE_StructGridSetNumGhost, ex->hgrid, sw); 153f4bdf6c4SBarry Smith 154f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 15508401ef6SPierre Jolivet PetscCheck(sw[0] <= 1, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Ask us to add support for wider stencils"); 15608401ef6SPierre Jolivet PetscCheck(st != DMDA_STENCIL_BOX, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Ask us to add support for box stencils"); 157f4bdf6c4SBarry Smith if (dim == 1) { 1582cf14000SStefano Zampini HYPRE_Int offsets[3][1] = {{-1}, {0}, {1}}; 159f4bdf6c4SBarry Smith ssize = 3; 160792fecdfSBarry Smith PetscCallExternal(HYPRE_StructStencilCreate, dim, ssize, &ex->hstencil); 16148a46eb9SPierre Jolivet for (i = 0; i < ssize; i++) PetscCallExternal(HYPRE_StructStencilSetElement, ex->hstencil, i, offsets[i]); 162f4bdf6c4SBarry Smith } else if (dim == 2) { 1639371c9d4SSatish Balay HYPRE_Int offsets[5][2] = { 1649371c9d4SSatish Balay {0, -1}, 1659371c9d4SSatish Balay {-1, 0 }, 1669371c9d4SSatish Balay {0, 0 }, 1679371c9d4SSatish Balay {1, 0 }, 1689371c9d4SSatish Balay {0, 1 } 1699371c9d4SSatish Balay }; 170f4bdf6c4SBarry Smith ssize = 5; 171792fecdfSBarry Smith PetscCallExternal(HYPRE_StructStencilCreate, dim, ssize, &ex->hstencil); 17248a46eb9SPierre Jolivet for (i = 0; i < ssize; i++) PetscCallExternal(HYPRE_StructStencilSetElement, ex->hstencil, i, offsets[i]); 173f4bdf6c4SBarry Smith } else if (dim == 3) { 1749371c9d4SSatish Balay HYPRE_Int offsets[7][3] = { 1759371c9d4SSatish Balay {0, 0, -1}, 1769371c9d4SSatish Balay {0, -1, 0 }, 1779371c9d4SSatish Balay {-1, 0, 0 }, 1789371c9d4SSatish Balay {0, 0, 0 }, 1799371c9d4SSatish Balay {1, 0, 0 }, 1809371c9d4SSatish Balay {0, 1, 0 }, 1819371c9d4SSatish Balay {0, 0, 1 } 1829371c9d4SSatish Balay }; 183f4bdf6c4SBarry Smith ssize = 7; 184792fecdfSBarry Smith PetscCallExternal(HYPRE_StructStencilCreate, dim, ssize, &ex->hstencil); 18548a46eb9SPierre Jolivet for (i = 0; i < ssize; i++) PetscCallExternal(HYPRE_StructStencilSetElement, ex->hstencil, i, offsets[i]); 186f4bdf6c4SBarry Smith } 187f4bdf6c4SBarry Smith 188f4bdf6c4SBarry Smith /* create the HYPRE vector for rhs and solution */ 189792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorCreate, ex->hcomm, ex->hgrid, &ex->hb); 190792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorCreate, ex->hcomm, ex->hgrid, &ex->hx); 191792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorInitialize, ex->hb); 192792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorInitialize, ex->hx); 193792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorAssemble, ex->hb); 194792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorAssemble, ex->hx); 195f4bdf6c4SBarry Smith 196f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 197792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixCreate, ex->hcomm, ex->hgrid, ex->hstencil, &ex->hmat); 198792fecdfSBarry Smith PetscCallExternal(HYPRE_StructGridDestroy, ex->hgrid); 199792fecdfSBarry Smith PetscCallExternal(HYPRE_StructStencilDestroy, ex->hstencil); 200f4bdf6c4SBarry Smith if (ex->needsinitialization) { 201792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixInitialize, ex->hmat); 202f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 203f4bdf6c4SBarry Smith } 204f4bdf6c4SBarry Smith 205f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 2069566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da, 0, 0, 0, &nx, &ny, &nz)); 2079566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat, dof * nx * ny * nz, dof * nx * ny * nz, PETSC_DECIDE, PETSC_DECIDE)); 2089566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->rmap, 1)); 2099566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->cmap, 1)); 2109566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->rmap)); 2119566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->cmap)); 21259cb773eSBarry Smith mat->preallocated = PETSC_TRUE; 213f4bdf6c4SBarry Smith 214f4bdf6c4SBarry Smith if (dim == 3) { 215f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 216f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 217f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 2188865f1eaSKarl Rupp 2199566063dSJacob Faibussowitsch /* PetscCall(MatZeroEntries_HYPREStruct_3d(mat)); */ 220ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only support for 3d DMDA currently"); 221f4bdf6c4SBarry Smith 222f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 2239566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &ex->rstart, NULL)); 2249566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da, <og)); 2259566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **)&ex->gindices)); 2269566063dSJacob Faibussowitsch PetscCall(DMDAGetGhostCorners(ex->da, 0, 0, 0, &ex->gnx, &ex->gnxgny, 0)); 227f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 2289566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da, &ex->xs, &ex->ys, &ex->zs, &ex->nx, &ex->ny, 0)); 229f4bdf6c4SBarry Smith ex->nxny = ex->nx * ex->ny; 230f4bdf6c4SBarry Smith PetscFunctionReturn(0); 231f4bdf6c4SBarry Smith } 232f4bdf6c4SBarry Smith 233*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_HYPREStruct(Mat A, Vec x, Vec y) 234*d71ae5a4SJacob Faibussowitsch { 235b026d285SBarry Smith const PetscScalar *xx; 236b026d285SBarry Smith PetscScalar *yy; 2374ddd07fcSJed Brown PetscInt ilower[3], iupper[3]; 2382cf14000SStefano Zampini HYPRE_Int hlower[3], hupper[3]; 239f4bdf6c4SBarry Smith Mat_HYPREStruct *mx = (Mat_HYPREStruct *)(A->data); 240f4bdf6c4SBarry Smith 241f4bdf6c4SBarry Smith PetscFunctionBegin; 2429566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(mx->da, &ilower[0], &ilower[1], &ilower[2], &iupper[0], &iupper[1], &iupper[2])); 2432cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 244f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 245f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 246f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 2472cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 2482cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 2492cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 2502cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 2512cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 2522cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 253f4bdf6c4SBarry Smith 254f4bdf6c4SBarry Smith /* copy x values over to hypre */ 255792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorSetConstantValues, mx->hb, 0.0); 2569566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x, &xx)); 257792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorSetBoxValues, mx->hb, hlower, hupper, (HYPRE_Complex *)xx); 2589566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x, &xx)); 259792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorAssemble, mx->hb); 260792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixMatvec, 1.0, mx->hmat, mx->hb, 0.0, mx->hx); 261f4bdf6c4SBarry Smith 262f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 2639566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &yy)); 264792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorGetBoxValues, mx->hx, hlower, hupper, (HYPRE_Complex *)yy); 2659566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &yy)); 266f4bdf6c4SBarry Smith PetscFunctionReturn(0); 267f4bdf6c4SBarry Smith } 268f4bdf6c4SBarry Smith 269*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat, MatAssemblyType mode) 270*d71ae5a4SJacob Faibussowitsch { 271f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 272f4bdf6c4SBarry Smith 273f4bdf6c4SBarry Smith PetscFunctionBegin; 274792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixAssemble, ex->hmat); 275792fecdfSBarry Smith /* PetscCallExternal(HYPRE_StructMatrixPrint,"dummy",ex->hmat,0); */ 276f4bdf6c4SBarry Smith PetscFunctionReturn(0); 277f4bdf6c4SBarry Smith } 278f4bdf6c4SBarry Smith 279*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat) 280*d71ae5a4SJacob Faibussowitsch { 281f4bdf6c4SBarry Smith PetscFunctionBegin; 282f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 283f4bdf6c4SBarry Smith PetscFunctionReturn(0); 284f4bdf6c4SBarry Smith } 285f4bdf6c4SBarry Smith 286*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_HYPREStruct(Mat mat) 287*d71ae5a4SJacob Faibussowitsch { 288f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct *)mat->data; 289f4bdf6c4SBarry Smith 290f4bdf6c4SBarry Smith PetscFunctionBegin; 291792fecdfSBarry Smith PetscCallExternal(HYPRE_StructMatrixDestroy, ex->hmat); 292792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorDestroy, ex->hx); 293792fecdfSBarry Smith PetscCallExternal(HYPRE_StructVectorDestroy, ex->hb); 2949566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)ex->da)); 2959566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_free(&(ex->hcomm))); 2969566063dSJacob Faibussowitsch PetscCall(PetscFree(ex)); 297f4bdf6c4SBarry Smith PetscFunctionReturn(0); 298f4bdf6c4SBarry Smith } 299f4bdf6c4SBarry Smith 300*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B) 301*d71ae5a4SJacob Faibussowitsch { 302f4bdf6c4SBarry Smith Mat_HYPREStruct *ex; 303f4bdf6c4SBarry Smith 304f4bdf6c4SBarry Smith PetscFunctionBegin; 3054dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&ex)); 306f4bdf6c4SBarry Smith B->data = (void *)ex; 307f4bdf6c4SBarry Smith B->rmap->bs = 1; 308f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 309f4bdf6c4SBarry Smith 310f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 311f4bdf6c4SBarry Smith 312f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 313f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPREStruct; 314f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPREStruct; 315f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPREStruct; 31659cb773eSBarry Smith B->ops->setup = MatSetUp_HYPREStruct; 317f4bdf6c4SBarry Smith 318f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 319f4bdf6c4SBarry Smith 3209566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)B), &(ex->hcomm))); 3219566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATHYPRESTRUCT)); 322f4bdf6c4SBarry Smith PetscFunctionReturn(0); 323f4bdf6c4SBarry Smith } 324f4bdf6c4SBarry Smith 325f4bdf6c4SBarry Smith /*MC 326f4bdf6c4SBarry Smith MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 327f4bdf6c4SBarry Smith based on the hypre HYPRE_SStructMatrix. 328f4bdf6c4SBarry Smith 329f4bdf6c4SBarry Smith Level: intermediate 330f4bdf6c4SBarry Smith 33195452b02SPatrick Sanan Notes: 33295452b02SPatrick Sanan Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 333b026d285SBarry Smith grid objects, we restrict the semi-struct objects to consist of only structured-grid components. 334f4bdf6c4SBarry Smith 335f4bdf6c4SBarry 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 336f4bdf6c4SBarry Smith be defined by a DMDA. 337f4bdf6c4SBarry Smith 33859cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 339f4bdf6c4SBarry Smith 340f4bdf6c4SBarry Smith M*/ 341f4bdf6c4SBarry Smith 342*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv) 343*d71ae5a4SJacob Faibussowitsch { 3442cf14000SStefano Zampini HYPRE_Int index[3], *entries; 3452cf14000SStefano Zampini PetscInt i, j, stencil; 34639accc25SStefano Zampini HYPRE_Complex *values = (HYPRE_Complex *)y; 347f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 348f4bdf6c4SBarry Smith 3494ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 3504ddd07fcSJed Brown PetscInt ordering; 3514ddd07fcSJed Brown PetscInt grid_rank, to_grid_rank; 3524ddd07fcSJed Brown PetscInt var_type, to_var_type; 3534ddd07fcSJed Brown PetscInt to_var_entry = 0; 3544ddd07fcSJed Brown PetscInt nvars = ex->nvars; 3552cf14000SStefano Zampini PetscInt row; 356f4bdf6c4SBarry Smith 357f4bdf6c4SBarry Smith PetscFunctionBegin; 3589566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7 * nvars, &entries)); 359f4bdf6c4SBarry Smith ordering = ex->dofs_order; /* ordering= 0 nodal ordering 360f4bdf6c4SBarry Smith 1 variable ordering */ 36161710fbeSStefano Zampini /* stencil entries are ordered by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 362f4bdf6c4SBarry Smith if (!ordering) { 363f4bdf6c4SBarry Smith for (i = 0; i < nrow; i++) { 364f4bdf6c4SBarry Smith grid_rank = irow[i] / nvars; 365f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 366f4bdf6c4SBarry Smith 367f4bdf6c4SBarry Smith for (j = 0; j < ncol; j++) { 368f4bdf6c4SBarry Smith to_grid_rank = icol[j] / nvars; 369f4bdf6c4SBarry Smith to_var_type = (icol[j] % nvars); 370f4bdf6c4SBarry Smith 371f4bdf6c4SBarry Smith to_var_entry = to_var_entry * 7; 372f4bdf6c4SBarry Smith entries[j] = to_var_entry; 373f4bdf6c4SBarry Smith 374f4bdf6c4SBarry Smith stencil = to_grid_rank - grid_rank; 375f4bdf6c4SBarry Smith if (!stencil) { 376f4bdf6c4SBarry Smith entries[j] += 3; 377f4bdf6c4SBarry Smith } else if (stencil == -1) { 378f4bdf6c4SBarry Smith entries[j] += 2; 379f4bdf6c4SBarry Smith } else if (stencil == 1) { 380f4bdf6c4SBarry Smith entries[j] += 4; 381f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 382f4bdf6c4SBarry Smith entries[j] += 1; 383f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 384f4bdf6c4SBarry Smith entries[j] += 5; 385f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 386f4bdf6c4SBarry Smith entries[j] += 0; 387f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 388f4bdf6c4SBarry Smith entries[j] += 6; 38963a3b9bcSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row %" PetscInt_FMT " local column %" PetscInt_FMT " have bad stencil %" PetscInt_FMT, irow[i], icol[j], stencil); 390f4bdf6c4SBarry Smith } 391f4bdf6c4SBarry Smith 392f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 3932cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 3942cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 3952cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 396f4bdf6c4SBarry Smith 397792fecdfSBarry Smith if (addv == ADD_VALUES) PetscCallExternal(HYPRE_SStructMatrixAddToValues, ex->ss_mat, part, index, var_type, ncol, entries, values); 398792fecdfSBarry Smith else PetscCallExternal(HYPRE_SStructMatrixSetValues, ex->ss_mat, part, index, var_type, ncol, entries, values); 399f4bdf6c4SBarry Smith values += ncol; 400f4bdf6c4SBarry Smith } 401f4bdf6c4SBarry Smith } else { 402f4bdf6c4SBarry Smith for (i = 0; i < nrow; i++) { 403f4bdf6c4SBarry Smith var_type = irow[i] / (ex->gnxgnygnz); 404f4bdf6c4SBarry Smith grid_rank = irow[i] - var_type * (ex->gnxgnygnz); 405f4bdf6c4SBarry Smith 406f4bdf6c4SBarry Smith for (j = 0; j < ncol; j++) { 407f4bdf6c4SBarry Smith to_var_type = icol[j] / (ex->gnxgnygnz); 408f4bdf6c4SBarry Smith to_grid_rank = icol[j] - to_var_type * (ex->gnxgnygnz); 409f4bdf6c4SBarry Smith 410f4bdf6c4SBarry Smith to_var_entry = to_var_entry * 7; 411f4bdf6c4SBarry Smith entries[j] = to_var_entry; 412f4bdf6c4SBarry Smith 413f4bdf6c4SBarry Smith stencil = to_grid_rank - grid_rank; 414f4bdf6c4SBarry Smith if (!stencil) { 415f4bdf6c4SBarry Smith entries[j] += 3; 416f4bdf6c4SBarry Smith } else if (stencil == -1) { 417f4bdf6c4SBarry Smith entries[j] += 2; 418f4bdf6c4SBarry Smith } else if (stencil == 1) { 419f4bdf6c4SBarry Smith entries[j] += 4; 420f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 421f4bdf6c4SBarry Smith entries[j] += 1; 422f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 423f4bdf6c4SBarry Smith entries[j] += 5; 424f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 425f4bdf6c4SBarry Smith entries[j] += 0; 426f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 427f4bdf6c4SBarry Smith entries[j] += 6; 42863a3b9bcSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row %" PetscInt_FMT " local column %" PetscInt_FMT " have bad stencil %" PetscInt_FMT, irow[i], icol[j], stencil); 429f4bdf6c4SBarry Smith } 430f4bdf6c4SBarry Smith 431f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4322cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4332cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 4342cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 435f4bdf6c4SBarry Smith 436792fecdfSBarry Smith if (addv == ADD_VALUES) PetscCallExternal(HYPRE_SStructMatrixAddToValues, ex->ss_mat, part, index, var_type, ncol, entries, values); 437792fecdfSBarry Smith else PetscCallExternal(HYPRE_SStructMatrixSetValues, ex->ss_mat, part, index, var_type, ncol, entries, values); 438f4bdf6c4SBarry Smith values += ncol; 439f4bdf6c4SBarry Smith } 440f4bdf6c4SBarry Smith } 4419566063dSJacob Faibussowitsch PetscCall(PetscFree(entries)); 442f4bdf6c4SBarry Smith PetscFunctionReturn(0); 443f4bdf6c4SBarry Smith } 444f4bdf6c4SBarry Smith 445*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat, PetscInt nrow, const PetscInt irow[], PetscScalar d, Vec x, Vec b) 446*d71ae5a4SJacob Faibussowitsch { 4472cf14000SStefano Zampini HYPRE_Int index[3], *entries; 4482cf14000SStefano Zampini PetscInt i; 44939accc25SStefano Zampini HYPRE_Complex **values; 450f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 451f4bdf6c4SBarry Smith 4524ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 4534ddd07fcSJed Brown PetscInt ordering = ex->dofs_order; 4544ddd07fcSJed Brown PetscInt grid_rank; 4554ddd07fcSJed Brown PetscInt var_type; 4564ddd07fcSJed Brown PetscInt nvars = ex->nvars; 4572cf14000SStefano Zampini PetscInt row; 458f4bdf6c4SBarry Smith 459f4bdf6c4SBarry Smith PetscFunctionBegin; 46008401ef6SPierre Jolivet PetscCheck(!x || !b, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "No support"); 4619566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7 * nvars, &entries)); 462f4bdf6c4SBarry Smith 4639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nvars, &values)); 4649566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7 * nvars * nvars, &values[0])); 465ad540459SPierre Jolivet for (i = 1; i < nvars; i++) values[i] = values[i - 1] + nvars * 7; 466f4bdf6c4SBarry Smith 467f4bdf6c4SBarry Smith for (i = 0; i < nvars; i++) { 4689566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values[i], nvars * 7 * sizeof(HYPRE_Complex))); 4699566063dSJacob Faibussowitsch PetscCall(PetscHYPREScalarCast(d, values[i] + 3)); 470f4bdf6c4SBarry Smith } 471f4bdf6c4SBarry Smith 4728865f1eaSKarl Rupp for (i = 0; i < nvars * 7; i++) entries[i] = i; 473f4bdf6c4SBarry Smith 474f4bdf6c4SBarry Smith if (!ordering) { 475f4bdf6c4SBarry Smith for (i = 0; i < nrow; i++) { 476f4bdf6c4SBarry Smith grid_rank = irow[i] / nvars; 477f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 478f4bdf6c4SBarry Smith 479f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4802cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4812cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 4822cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 483792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixSetValues, ex->ss_mat, part, index, var_type, 7 * nvars, entries, values[var_type]); 484f4bdf6c4SBarry Smith } 485f4bdf6c4SBarry Smith } else { 486f4bdf6c4SBarry Smith for (i = 0; i < nrow; i++) { 487f4bdf6c4SBarry Smith var_type = irow[i] / (ex->gnxgnygnz); 488f4bdf6c4SBarry Smith grid_rank = irow[i] - var_type * (ex->gnxgnygnz); 489f4bdf6c4SBarry Smith 490f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4912cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4922cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row / ex->nx) % ex->ny)); 4932cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row / (ex->nxny))); 494792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixSetValues, ex->ss_mat, part, index, var_type, 7 * nvars, entries, values[var_type]); 495f4bdf6c4SBarry Smith } 496f4bdf6c4SBarry Smith } 497792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixAssemble, ex->ss_mat); 4989566063dSJacob Faibussowitsch PetscCall(PetscFree(values[0])); 4999566063dSJacob Faibussowitsch PetscCall(PetscFree(values)); 5009566063dSJacob Faibussowitsch PetscCall(PetscFree(entries)); 501f4bdf6c4SBarry Smith PetscFunctionReturn(0); 502f4bdf6c4SBarry Smith } 503f4bdf6c4SBarry Smith 504*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 505*d71ae5a4SJacob Faibussowitsch { 506f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 5074ddd07fcSJed Brown PetscInt nvars = ex->nvars; 5084ddd07fcSJed Brown PetscInt size; 5094ddd07fcSJed Brown PetscInt part = 0; /* only one part */ 510f4bdf6c4SBarry Smith 511f4bdf6c4SBarry Smith PetscFunctionBegin; 512f4bdf6c4SBarry 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); 513f4bdf6c4SBarry Smith { 5142cf14000SStefano Zampini HYPRE_Int i, *entries, iupper[3], ilower[3]; 51539accc25SStefano Zampini HYPRE_Complex *values; 5164ddd07fcSJed Brown 517f4bdf6c4SBarry Smith for (i = 0; i < 3; i++) { 518f4bdf6c4SBarry Smith ilower[i] = ex->hbox.imin[i]; 519f4bdf6c4SBarry Smith iupper[i] = ex->hbox.imax[i]; 520f4bdf6c4SBarry Smith } 521f4bdf6c4SBarry Smith 5229566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nvars * 7, &entries, nvars * 7 * size, &values)); 5238865f1eaSKarl Rupp for (i = 0; i < nvars * 7; i++) entries[i] = i; 5249566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values, nvars * 7 * size)); 525f4bdf6c4SBarry Smith 52648a46eb9SPierre Jolivet for (i = 0; i < nvars; i++) PetscCallExternal(HYPRE_SStructMatrixSetBoxValues, ex->ss_mat, part, ilower, iupper, i, nvars * 7, entries, values); 5279566063dSJacob Faibussowitsch PetscCall(PetscFree2(entries, values)); 528f4bdf6c4SBarry Smith } 529792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixAssemble, ex->ss_mat); 530f4bdf6c4SBarry Smith PetscFunctionReturn(0); 531f4bdf6c4SBarry Smith } 532f4bdf6c4SBarry Smith 533*d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_HYPRESStruct(Mat mat) 534*d71ae5a4SJacob Faibussowitsch { 535f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 536f4bdf6c4SBarry Smith PetscInt dim, dof, sw[3], nx, ny, nz; 5374ddd07fcSJed Brown PetscInt ilower[3], iupper[3], ssize, i; 538bff4a2f0SMatthew G. Knepley DMBoundaryType px, py, pz; 539f4bdf6c4SBarry Smith DMDAStencilType st; 5404ddd07fcSJed Brown PetscInt nparts = 1; /* assuming only one part */ 5414ddd07fcSJed Brown PetscInt part = 0; 542565245c5SBarry Smith ISLocalToGlobalMapping ltog; 54359cb773eSBarry Smith DM da; 544b026d285SBarry Smith 545f4bdf6c4SBarry Smith PetscFunctionBegin; 5469566063dSJacob Faibussowitsch PetscCall(MatGetDM(mat, (DM *)&da)); 547f4bdf6c4SBarry Smith ex->da = da; 5489566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)da)); 549f4bdf6c4SBarry Smith 5509566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(ex->da, &dim, 0, 0, 0, 0, 0, 0, &dof, &sw[0], &px, &py, &pz, &st)); 5519566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da, &ilower[0], &ilower[1], &ilower[2], &iupper[0], &iupper[1], &iupper[2])); 552f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 553f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 554f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 555f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 556f4bdf6c4SBarry Smith ex->hbox.imin[0] = ilower[0]; 557f4bdf6c4SBarry Smith ex->hbox.imin[1] = ilower[1]; 558f4bdf6c4SBarry Smith ex->hbox.imin[2] = ilower[2]; 559f4bdf6c4SBarry Smith ex->hbox.imax[0] = iupper[0]; 560f4bdf6c4SBarry Smith ex->hbox.imax[1] = iupper[1]; 561f4bdf6c4SBarry Smith ex->hbox.imax[2] = iupper[2]; 562f4bdf6c4SBarry Smith 563f4bdf6c4SBarry Smith ex->dofs_order = 0; 564f4bdf6c4SBarry Smith 565f4bdf6c4SBarry Smith /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */ 566f4bdf6c4SBarry Smith ex->nvars = dof; 567f4bdf6c4SBarry Smith 568f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 5691dca8a05SBarry Smith PetscCheck(!px && !py && !pz, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 570792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGridCreate, ex->hcomm, dim, nparts, &ex->ss_grid); 571792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGridSetExtents, ex->ss_grid, part, ex->hbox.imin, ex->hbox.imax); 572f4bdf6c4SBarry Smith { 573f4bdf6c4SBarry Smith HYPRE_SStructVariable *vartypes; 5749566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ex->nvars, &vartypes)); 5758865f1eaSKarl Rupp for (i = 0; i < ex->nvars; i++) vartypes[i] = HYPRE_SSTRUCT_VARIABLE_CELL; 576792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGridSetVariables, ex->ss_grid, part, ex->nvars, vartypes); 5779566063dSJacob Faibussowitsch PetscCall(PetscFree(vartypes)); 578f4bdf6c4SBarry Smith } 579792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGridAssemble, ex->ss_grid); 580f4bdf6c4SBarry Smith 581f4bdf6c4SBarry Smith sw[1] = sw[0]; 582f4bdf6c4SBarry Smith sw[2] = sw[1]; 583792fecdfSBarry Smith /* PetscCallExternal(HYPRE_SStructGridSetNumGhost,ex->ss_grid,sw); */ 584f4bdf6c4SBarry Smith 585f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 58608401ef6SPierre Jolivet PetscCheck(sw[0] <= 1, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Ask us to add support for wider stencils"); 58708401ef6SPierre Jolivet PetscCheck(st != DMDA_STENCIL_BOX, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Ask us to add support for box stencils"); 588f4bdf6c4SBarry Smith 589f4bdf6c4SBarry Smith if (dim == 1) { 5902cf14000SStefano Zampini HYPRE_Int offsets[3][1] = {{-1}, {0}, {1}}; 5914ddd07fcSJed Brown PetscInt j, cnt; 592f4bdf6c4SBarry Smith 593f4bdf6c4SBarry Smith ssize = 3 * (ex->nvars); 594792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilCreate, dim, ssize, &ex->ss_stencil); 595f4bdf6c4SBarry Smith cnt = 0; 596f4bdf6c4SBarry Smith for (i = 0; i < (ex->nvars); i++) { 597f4bdf6c4SBarry Smith for (j = 0; j < 3; j++) { 598792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilSetEntry, ex->ss_stencil, cnt, offsets[j], i); 599f4bdf6c4SBarry Smith cnt++; 600f4bdf6c4SBarry Smith } 601f4bdf6c4SBarry Smith } 602f4bdf6c4SBarry Smith } else if (dim == 2) { 6039371c9d4SSatish Balay HYPRE_Int offsets[5][2] = { 6049371c9d4SSatish Balay {0, -1}, 6059371c9d4SSatish Balay {-1, 0 }, 6069371c9d4SSatish Balay {0, 0 }, 6079371c9d4SSatish Balay {1, 0 }, 6089371c9d4SSatish Balay {0, 1 } 6099371c9d4SSatish Balay }; 6104ddd07fcSJed Brown PetscInt j, cnt; 611f4bdf6c4SBarry Smith 612f4bdf6c4SBarry Smith ssize = 5 * (ex->nvars); 613792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilCreate, dim, ssize, &ex->ss_stencil); 614f4bdf6c4SBarry Smith cnt = 0; 615f4bdf6c4SBarry Smith for (i = 0; i < (ex->nvars); i++) { 616f4bdf6c4SBarry Smith for (j = 0; j < 5; j++) { 617792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilSetEntry, ex->ss_stencil, cnt, offsets[j], i); 618f4bdf6c4SBarry Smith cnt++; 619f4bdf6c4SBarry Smith } 620f4bdf6c4SBarry Smith } 621f4bdf6c4SBarry Smith } else if (dim == 3) { 6229371c9d4SSatish Balay HYPRE_Int offsets[7][3] = { 6239371c9d4SSatish Balay {0, 0, -1}, 6249371c9d4SSatish Balay {0, -1, 0 }, 6259371c9d4SSatish Balay {-1, 0, 0 }, 6269371c9d4SSatish Balay {0, 0, 0 }, 6279371c9d4SSatish Balay {1, 0, 0 }, 6289371c9d4SSatish Balay {0, 1, 0 }, 6299371c9d4SSatish Balay {0, 0, 1 } 6309371c9d4SSatish Balay }; 6314ddd07fcSJed Brown PetscInt j, cnt; 632f4bdf6c4SBarry Smith 633f4bdf6c4SBarry Smith ssize = 7 * (ex->nvars); 634792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilCreate, dim, ssize, &ex->ss_stencil); 635f4bdf6c4SBarry Smith cnt = 0; 636f4bdf6c4SBarry Smith for (i = 0; i < (ex->nvars); i++) { 637f4bdf6c4SBarry Smith for (j = 0; j < 7; j++) { 638792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilSetEntry, ex->ss_stencil, cnt, offsets[j], i); 639f4bdf6c4SBarry Smith cnt++; 640f4bdf6c4SBarry Smith } 641f4bdf6c4SBarry Smith } 642f4bdf6c4SBarry Smith } 643f4bdf6c4SBarry Smith 644f4bdf6c4SBarry Smith /* create the HYPRE graph */ 645792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGraphCreate, ex->hcomm, ex->ss_grid, &(ex->ss_graph)); 646f4bdf6c4SBarry Smith 647f4bdf6c4SBarry Smith /* set the stencil graph. Note that each variable has the same graph. This means that each 648f4bdf6c4SBarry Smith variable couples to all the other variable and with the same stencil pattern. */ 64948a46eb9SPierre Jolivet for (i = 0; i < (ex->nvars); i++) PetscCallExternal(HYPRE_SStructGraphSetStencil, ex->ss_graph, part, i, ex->ss_stencil); 650792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGraphAssemble, ex->ss_graph); 651f4bdf6c4SBarry Smith 652f4bdf6c4SBarry Smith /* create the HYPRE sstruct vectors for rhs and solution */ 653792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorCreate, ex->hcomm, ex->ss_grid, &ex->ss_b); 654792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorCreate, ex->hcomm, ex->ss_grid, &ex->ss_x); 655792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorInitialize, ex->ss_b); 656792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorInitialize, ex->ss_x); 657792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorAssemble, ex->ss_b); 658792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorAssemble, ex->ss_x); 659f4bdf6c4SBarry Smith 660f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 661792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixCreate, ex->hcomm, ex->ss_graph, &ex->ss_mat); 662792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGridDestroy, ex->ss_grid); 663792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructStencilDestroy, ex->ss_stencil); 664f4bdf6c4SBarry Smith if (ex->needsinitialization) { 665792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixInitialize, ex->ss_mat); 666f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 667f4bdf6c4SBarry Smith } 668f4bdf6c4SBarry Smith 669f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 6709566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da, 0, 0, 0, &nx, &ny, &nz)); 6719566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat, dof * nx * ny * nz, dof * nx * ny * nz, PETSC_DECIDE, PETSC_DECIDE)); 6729566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->rmap, dof)); 6739566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->cmap, dof)); 6749566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->rmap)); 6759566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->cmap)); 67661710fbeSStefano Zampini mat->preallocated = PETSC_TRUE; 677f4bdf6c4SBarry Smith 678f4bdf6c4SBarry Smith if (dim == 3) { 679f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 680f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 681f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 6828865f1eaSKarl Rupp 6839566063dSJacob Faibussowitsch /* PetscCall(MatZeroEntries_HYPRESStruct_3d(mat)); */ 684ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only support for 3d DMDA currently"); 685f4bdf6c4SBarry Smith 686f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 6879566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &ex->rstart, NULL)); 6889566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da, <og)); 6899566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **)&ex->gindices)); 6909566063dSJacob Faibussowitsch PetscCall(DMDAGetGhostCorners(ex->da, 0, 0, 0, &ex->gnx, &ex->gnxgny, &ex->gnxgnygnz)); 6918865f1eaSKarl Rupp 692f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 693f4bdf6c4SBarry Smith ex->gnxgnygnz *= ex->gnxgny; 6948865f1eaSKarl Rupp 6959566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da, &ex->xs, &ex->ys, &ex->zs, &ex->nx, &ex->ny, &ex->nz)); 6968865f1eaSKarl Rupp 697f4bdf6c4SBarry Smith ex->nxny = ex->nx * ex->ny; 698f4bdf6c4SBarry Smith ex->nxnynz = ex->nz * ex->nxny; 699f4bdf6c4SBarry Smith PetscFunctionReturn(0); 700f4bdf6c4SBarry Smith } 701f4bdf6c4SBarry Smith 702*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_HYPRESStruct(Mat A, Vec x, Vec y) 703*d71ae5a4SJacob Faibussowitsch { 704b026d285SBarry Smith const PetscScalar *xx; 705b026d285SBarry Smith PetscScalar *yy; 7062cf14000SStefano Zampini HYPRE_Int hlower[3], hupper[3]; 7074ddd07fcSJed Brown PetscInt ilower[3], iupper[3]; 708f4bdf6c4SBarry Smith Mat_HYPRESStruct *mx = (Mat_HYPRESStruct *)(A->data); 7094ddd07fcSJed Brown PetscInt ordering = mx->dofs_order; 7104ddd07fcSJed Brown PetscInt nvars = mx->nvars; 7114ddd07fcSJed Brown PetscInt part = 0; 7124ddd07fcSJed Brown PetscInt size; 7134ddd07fcSJed Brown PetscInt i; 714f4bdf6c4SBarry Smith 715f4bdf6c4SBarry Smith PetscFunctionBegin; 7169566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(mx->da, &ilower[0], &ilower[1], &ilower[2], &iupper[0], &iupper[1], &iupper[2])); 7172cf14000SStefano Zampini 7182cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 719f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 720f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 721f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 7222cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 7232cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 7242cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 7252cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 7262cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 7272cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 728f4bdf6c4SBarry Smith 729f4bdf6c4SBarry Smith size = 1; 7308865f1eaSKarl Rupp for (i = 0; i < 3; i++) size *= (iupper[i] - ilower[i] + 1); 731f4bdf6c4SBarry Smith 732f4bdf6c4SBarry Smith /* copy x values over to hypre for variable ordering */ 733f4bdf6c4SBarry Smith if (ordering) { 734792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorSetConstantValues, mx->ss_b, 0.0); 7359566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x, &xx)); 73648a46eb9SPierre Jolivet for (i = 0; i < nvars; i++) PetscCallExternal(HYPRE_SStructVectorSetBoxValues, mx->ss_b, part, hlower, hupper, i, (HYPRE_Complex *)(xx + (size * i))); 7379566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x, &xx)); 738792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorAssemble, mx->ss_b); 739792fecdfSBarry Smith PetscCallExternal(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 */ 7429566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &yy)); 74348a46eb9SPierre Jolivet for (i = 0; i < nvars; i++) PetscCallExternal(HYPRE_SStructVectorGetBoxValues, mx->ss_x, part, hlower, hupper, i, (HYPRE_Complex *)(yy + (size * i))); 7449566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &yy)); 745f4bdf6c4SBarry Smith } else { /* nodal ordering must be mapped to variable ordering for sys_pfmg */ 746f4bdf6c4SBarry Smith PetscScalar *z; 7474ddd07fcSJed Brown PetscInt j, k; 748f4bdf6c4SBarry Smith 7499566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nvars * size, &z)); 750792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorSetConstantValues, mx->ss_b, 0.0); 7519566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x, &xx)); 752f4bdf6c4SBarry Smith 753f4bdf6c4SBarry Smith /* transform nodal to hypre's variable ordering for sys_pfmg */ 754f4bdf6c4SBarry Smith for (i = 0; i < size; i++) { 755f4bdf6c4SBarry Smith k = i * nvars; 7568865f1eaSKarl Rupp for (j = 0; j < nvars; j++) z[j * size + i] = xx[k + j]; 757f4bdf6c4SBarry Smith } 75848a46eb9SPierre Jolivet for (i = 0; i < nvars; i++) PetscCallExternal(HYPRE_SStructVectorSetBoxValues, mx->ss_b, part, hlower, hupper, i, (HYPRE_Complex *)(z + (size * i))); 7599566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x, &xx)); 760792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorAssemble, mx->ss_b); 761792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixMatvec, 1.0, mx->ss_mat, mx->ss_b, 0.0, mx->ss_x); 762f4bdf6c4SBarry Smith 763f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 7649566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &yy)); 76548a46eb9SPierre Jolivet for (i = 0; i < nvars; i++) PetscCallExternal(HYPRE_SStructVectorGetBoxValues, mx->ss_x, part, hlower, hupper, i, (HYPRE_Complex *)(z + (size * i))); 766f4bdf6c4SBarry Smith /* transform hypre's variable ordering for sys_pfmg to nodal ordering */ 767f4bdf6c4SBarry Smith for (i = 0; i < size; i++) { 768f4bdf6c4SBarry Smith k = i * nvars; 7698865f1eaSKarl Rupp for (j = 0; j < nvars; j++) yy[k + j] = z[j * size + i]; 770f4bdf6c4SBarry Smith } 7719566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &yy)); 7729566063dSJacob Faibussowitsch PetscCall(PetscFree(z)); 773f4bdf6c4SBarry Smith } 774f4bdf6c4SBarry Smith PetscFunctionReturn(0); 775f4bdf6c4SBarry Smith } 776f4bdf6c4SBarry Smith 777*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat, MatAssemblyType mode) 778*d71ae5a4SJacob Faibussowitsch { 779f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 780f4bdf6c4SBarry Smith 781f4bdf6c4SBarry Smith PetscFunctionBegin; 782792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixAssemble, ex->ss_mat); 783f4bdf6c4SBarry Smith PetscFunctionReturn(0); 784f4bdf6c4SBarry Smith } 785f4bdf6c4SBarry Smith 786*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat) 787*d71ae5a4SJacob Faibussowitsch { 788f4bdf6c4SBarry Smith PetscFunctionBegin; 789f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 790f4bdf6c4SBarry Smith PetscFunctionReturn(0); 791f4bdf6c4SBarry Smith } 792f4bdf6c4SBarry Smith 793*d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_HYPRESStruct(Mat mat) 794*d71ae5a4SJacob Faibussowitsch { 795f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct *)mat->data; 796d94fc0b6SBarry Smith ISLocalToGlobalMapping ltog; 797f4bdf6c4SBarry Smith 798f4bdf6c4SBarry Smith PetscFunctionBegin; 7999566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da, <og)); 8009566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **)&ex->gindices)); 801792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructGraphDestroy, ex->ss_graph); 802792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructMatrixDestroy, ex->ss_mat); 803792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorDestroy, ex->ss_x); 804792fecdfSBarry Smith PetscCallExternal(HYPRE_SStructVectorDestroy, ex->ss_b); 8059566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)ex->da)); 8069566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_free(&(ex->hcomm))); 8079566063dSJacob Faibussowitsch PetscCall(PetscFree(ex)); 808f4bdf6c4SBarry Smith PetscFunctionReturn(0); 809f4bdf6c4SBarry Smith } 810f4bdf6c4SBarry Smith 811*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B) 812*d71ae5a4SJacob Faibussowitsch { 813f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex; 814f4bdf6c4SBarry Smith 815f4bdf6c4SBarry Smith PetscFunctionBegin; 8164dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&ex)); 817f4bdf6c4SBarry Smith B->data = (void *)ex; 818f4bdf6c4SBarry Smith B->rmap->bs = 1; 819f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 820f4bdf6c4SBarry Smith 821f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 822f4bdf6c4SBarry Smith 823f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 824f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPRESStruct; 825f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 826f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPRESStruct; 82759cb773eSBarry Smith B->ops->setup = MatSetUp_HYPRESStruct; 828f4bdf6c4SBarry Smith 829f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 830f4bdf6c4SBarry Smith 8319566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)B), &(ex->hcomm))); 8329566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATHYPRESSTRUCT)); 833f4bdf6c4SBarry Smith PetscFunctionReturn(0); 834f4bdf6c4SBarry Smith } 835