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 2559cb773eSBarry Smith .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix() 26f4bdf6c4SBarry Smith M*/ 27f4bdf6c4SBarry Smith 28f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 29f4bdf6c4SBarry Smith { 302cf14000SStefano Zampini HYPRE_Int index[3],entries[7]; 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; 36*08401ef6SPierre Jolivet PetscCheck(ncol <= 7,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"ncol %D > 7 too large",ncol); 37f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 38f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 39f4bdf6c4SBarry Smith stencil = icol[j] - irow[i]; 40f4bdf6c4SBarry Smith if (!stencil) { 41f4bdf6c4SBarry Smith entries[j] = 3; 42f4bdf6c4SBarry Smith } else if (stencil == -1) { 43f4bdf6c4SBarry Smith entries[j] = 2; 44f4bdf6c4SBarry Smith } else if (stencil == 1) { 45f4bdf6c4SBarry Smith entries[j] = 4; 46f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 47f4bdf6c4SBarry Smith entries[j] = 1; 48f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 49f4bdf6c4SBarry Smith entries[j] = 5; 50f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 51f4bdf6c4SBarry Smith entries[j] = 0; 52f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 53f4bdf6c4SBarry Smith entries[j] = 6; 5498921bdaSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 55f4bdf6c4SBarry Smith } 56f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 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))); 60f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 61a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixAddToValues,ex->hmat,index,ncol,entries,values); 62f4bdf6c4SBarry Smith } else { 63a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixSetValues,ex->hmat,index,ncol,entries,values); 64f4bdf6c4SBarry Smith } 65f4bdf6c4SBarry Smith values += ncol; 66f4bdf6c4SBarry Smith } 67f4bdf6c4SBarry Smith PetscFunctionReturn(0); 68f4bdf6c4SBarry Smith } 69f4bdf6c4SBarry Smith 70f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 71f4bdf6c4SBarry Smith { 722cf14000SStefano Zampini HYPRE_Int index[3],entries[7] = {0,1,2,3,4,5,6}; 732cf14000SStefano Zampini PetscInt row,i; 7439accc25SStefano Zampini HYPRE_Complex values[7]; 75f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 76f4bdf6c4SBarry Smith 77f4bdf6c4SBarry Smith PetscFunctionBegin; 78*08401ef6SPierre Jolivet PetscCheck(!x || !b,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 799566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values,7)); 809566063dSJacob Faibussowitsch PetscCall(PetscHYPREScalarCast(d,&values[3])); 81f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 82f4bdf6c4SBarry Smith row = ex->gindices[irow[i]] - ex->rstart; 832cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 842cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny)); 852cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny))); 86a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixSetValues,ex->hmat,index,7,entries,values); 87f4bdf6c4SBarry Smith } 88a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixAssemble,ex->hmat); 89f4bdf6c4SBarry Smith PetscFunctionReturn(0); 90f4bdf6c4SBarry Smith } 91f4bdf6c4SBarry Smith 92f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat) 93f4bdf6c4SBarry Smith { 942cf14000SStefano Zampini HYPRE_Int 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 */ 99a74df02fSJacob Faibussowitsch PetscStackCallStandard(hypre_StructMatrixClearBoxValues,ex->hmat,&ex->hbox,7,indices,0,1); 100a74df02fSJacob Faibussowitsch 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 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 1072cf14000SStefano Zampini HYPRE_Int sw[6]; 1082cf14000SStefano Zampini HYPRE_Int hlower[3],hupper[3]; 1092cf14000SStefano Zampini PetscInt dim,dof,psw,nx,ny,nz,ilower[3],iupper[3],ssize,i; 110bff4a2f0SMatthew G. Knepley DMBoundaryType px,py,pz; 111f4bdf6c4SBarry Smith DMDAStencilType st; 112565245c5SBarry Smith ISLocalToGlobalMapping ltog; 11359cb773eSBarry Smith DM da; 114f4bdf6c4SBarry Smith 115f4bdf6c4SBarry Smith PetscFunctionBegin; 1169566063dSJacob Faibussowitsch PetscCall(MatGetDM(mat,(DM*)&da)); 117f4bdf6c4SBarry Smith ex->da = da; 1189566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)da)); 119f4bdf6c4SBarry Smith 1209566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&psw,&px,&py,&pz,&st)); 1219566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2])); 1222cf14000SStefano Zampini 1232cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 124f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 125f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 126f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 1272cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 1282cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 1292cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 1302cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 1312cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 1322cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 133f4bdf6c4SBarry Smith 134f4bdf6c4SBarry Smith /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 1352cf14000SStefano Zampini ex->hbox.imin[0] = hlower[0]; 1362cf14000SStefano Zampini ex->hbox.imin[1] = hlower[1]; 1372cf14000SStefano Zampini ex->hbox.imin[2] = hlower[2]; 1382cf14000SStefano Zampini ex->hbox.imax[0] = hupper[0]; 1392cf14000SStefano Zampini ex->hbox.imax[1] = hupper[1]; 1402cf14000SStefano Zampini ex->hbox.imax[2] = hupper[2]; 141f4bdf6c4SBarry Smith 142f4bdf6c4SBarry Smith /* create the hypre grid object and set its information */ 143*08401ef6SPierre Jolivet PetscCheck(dof <= 1,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems"); 1442c71b3e2SJacob Faibussowitsch PetscCheckFalse(px || py || pz,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()"); 145a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructGridCreate,ex->hcomm,dim,&ex->hgrid); 146a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructGridSetExtents,ex->hgrid,hlower,hupper); 147a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructGridAssemble,ex->hgrid); 148f4bdf6c4SBarry Smith 1492cf14000SStefano Zampini sw[5] = sw[4] = sw[3] = sw[2] = sw[1] = sw[0] = psw; 150a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructGridSetNumGhost,ex->hgrid,sw); 151f4bdf6c4SBarry Smith 152f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 153*08401ef6SPierre Jolivet PetscCheck(sw[0] <= 1,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 154*08401ef6SPierre Jolivet PetscCheck(st != DMDA_STENCIL_BOX,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 155f4bdf6c4SBarry Smith if (dim == 1) { 1562cf14000SStefano Zampini HYPRE_Int offsets[3][1] = {{-1},{0},{1}}; 157f4bdf6c4SBarry Smith ssize = 3; 158a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil); 159f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 160a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]); 161f4bdf6c4SBarry Smith } 162f4bdf6c4SBarry Smith } else if (dim == 2) { 1632cf14000SStefano Zampini HYPRE_Int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 164f4bdf6c4SBarry Smith ssize = 5; 165a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil); 166f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 167a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]); 168f4bdf6c4SBarry Smith } 169f4bdf6c4SBarry Smith } else if (dim == 3) { 1702cf14000SStefano Zampini HYPRE_Int offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; 171f4bdf6c4SBarry Smith ssize = 7; 172a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilCreate,dim,ssize,&ex->hstencil); 173f4bdf6c4SBarry Smith for (i=0; i<ssize; i++) { 174a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilSetElement,ex->hstencil,i,offsets[i]); 175f4bdf6c4SBarry Smith } 176f4bdf6c4SBarry Smith } 177f4bdf6c4SBarry Smith 178f4bdf6c4SBarry Smith /* create the HYPRE vector for rhs and solution */ 179a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorCreate,ex->hcomm,ex->hgrid,&ex->hb); 180a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorCreate,ex->hcomm,ex->hgrid,&ex->hx); 181a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorInitialize,ex->hb); 182a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorInitialize,ex->hx); 183a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorAssemble,ex->hb); 184a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorAssemble,ex->hx); 185f4bdf6c4SBarry Smith 186f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 187a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixCreate,ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat); 188a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructGridDestroy,ex->hgrid); 189a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructStencilDestroy,ex->hstencil); 190f4bdf6c4SBarry Smith if (ex->needsinitialization) { 191a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixInitialize,ex->hmat); 192f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 193f4bdf6c4SBarry Smith } 194f4bdf6c4SBarry Smith 195f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 1969566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da,0,0,0,&nx,&ny,&nz)); 1979566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE)); 1989566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->rmap,1)); 1999566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->cmap,1)); 2009566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->rmap)); 2019566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->cmap)); 20259cb773eSBarry Smith mat->preallocated = PETSC_TRUE; 203f4bdf6c4SBarry Smith 204f4bdf6c4SBarry Smith if (dim == 3) { 205f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 206f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 207f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 2088865f1eaSKarl Rupp 2099566063dSJacob Faibussowitsch /* PetscCall(MatZeroEntries_HYPREStruct_3d(mat)); */ 210ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 211f4bdf6c4SBarry Smith 212f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 2139566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat,&ex->rstart,NULL)); 2149566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da,<og)); 2159566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices)); 2169566063dSJacob Faibussowitsch PetscCall(DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0)); 217f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 2189566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0)); 219f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 220f4bdf6c4SBarry Smith PetscFunctionReturn(0); 221f4bdf6c4SBarry Smith } 222f4bdf6c4SBarry Smith 223f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y) 224f4bdf6c4SBarry Smith { 225b026d285SBarry Smith const PetscScalar *xx; 226b026d285SBarry Smith PetscScalar *yy; 2274ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 2282cf14000SStefano Zampini HYPRE_Int hlower[3],hupper[3]; 229f4bdf6c4SBarry Smith Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data); 230f4bdf6c4SBarry Smith 231f4bdf6c4SBarry Smith PetscFunctionBegin; 2329566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2])); 2332cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 234f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 235f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 236f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 2372cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 2382cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 2392cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 2402cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 2412cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 2422cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 243f4bdf6c4SBarry Smith 244f4bdf6c4SBarry Smith /* copy x values over to hypre */ 245a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,mx->hb,0.0); 2469566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x,&xx)); 247a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,mx->hb,hlower,hupper,(HYPRE_Complex*)xx); 2489566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x,&xx)); 249a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorAssemble,mx->hb); 250a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixMatvec,1.0,mx->hmat,mx->hb,0.0,mx->hx); 251f4bdf6c4SBarry Smith 252f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 2539566063dSJacob Faibussowitsch PetscCall(VecGetArray(y,&yy)); 254a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,mx->hx,hlower,hupper,(HYPRE_Complex*)yy); 2559566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y,&yy)); 256f4bdf6c4SBarry Smith PetscFunctionReturn(0); 257f4bdf6c4SBarry Smith } 258f4bdf6c4SBarry Smith 259f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode) 260f4bdf6c4SBarry Smith { 261f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 262f4bdf6c4SBarry Smith 263f4bdf6c4SBarry Smith PetscFunctionBegin; 264a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixAssemble,ex->hmat); 265a74df02fSJacob Faibussowitsch /* PetscStackCallStandard(HYPRE_StructMatrixPrint,"dummy",ex->hmat,0); */ 266f4bdf6c4SBarry Smith PetscFunctionReturn(0); 267f4bdf6c4SBarry Smith } 268f4bdf6c4SBarry Smith 269f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat) 270f4bdf6c4SBarry Smith { 271f4bdf6c4SBarry Smith PetscFunctionBegin; 272f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 273f4bdf6c4SBarry Smith PetscFunctionReturn(0); 274f4bdf6c4SBarry Smith } 275f4bdf6c4SBarry Smith 276f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPREStruct(Mat mat) 277f4bdf6c4SBarry Smith { 278f4bdf6c4SBarry Smith Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 279f4bdf6c4SBarry Smith 280f4bdf6c4SBarry Smith PetscFunctionBegin; 281a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructMatrixDestroy,ex->hmat); 282a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorDestroy,ex->hx); 283a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_StructVectorDestroy,ex->hb); 2849566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)ex->da)); 2859566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_free(&(ex->hcomm))); 2869566063dSJacob Faibussowitsch PetscCall(PetscFree(ex)); 287f4bdf6c4SBarry Smith PetscFunctionReturn(0); 288f4bdf6c4SBarry Smith } 289f4bdf6c4SBarry Smith 2908cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B) 291f4bdf6c4SBarry Smith { 292f4bdf6c4SBarry Smith Mat_HYPREStruct *ex; 293f4bdf6c4SBarry Smith 294f4bdf6c4SBarry Smith PetscFunctionBegin; 2959566063dSJacob Faibussowitsch PetscCall(PetscNewLog(B,&ex)); 296f4bdf6c4SBarry Smith B->data = (void*)ex; 297f4bdf6c4SBarry Smith B->rmap->bs = 1; 298f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 299f4bdf6c4SBarry Smith 300f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 301f4bdf6c4SBarry Smith 302f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 303f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPREStruct; 304f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPREStruct; 305f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPREStruct; 30659cb773eSBarry Smith B->ops->setup = MatSetUp_HYPREStruct; 307f4bdf6c4SBarry Smith 308f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 309f4bdf6c4SBarry Smith 3109566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm))); 3119566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT)); 312f4bdf6c4SBarry Smith PetscFunctionReturn(0); 313f4bdf6c4SBarry Smith } 314f4bdf6c4SBarry Smith 315f4bdf6c4SBarry Smith /*MC 316f4bdf6c4SBarry Smith MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 317f4bdf6c4SBarry Smith based on the hypre HYPRE_SStructMatrix. 318f4bdf6c4SBarry Smith 319f4bdf6c4SBarry Smith Level: intermediate 320f4bdf6c4SBarry Smith 32195452b02SPatrick Sanan Notes: 32295452b02SPatrick Sanan Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 323b026d285SBarry Smith grid objects, we restrict the semi-struct objects to consist of only structured-grid components. 324f4bdf6c4SBarry Smith 325f4bdf6c4SBarry 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 326f4bdf6c4SBarry Smith be defined by a DMDA. 327f4bdf6c4SBarry Smith 32859cb773eSBarry Smith The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 329f4bdf6c4SBarry Smith 330f4bdf6c4SBarry Smith M*/ 331f4bdf6c4SBarry Smith 332f4bdf6c4SBarry Smith PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 333f4bdf6c4SBarry Smith { 3342cf14000SStefano Zampini HYPRE_Int index[3],*entries; 3352cf14000SStefano Zampini PetscInt i,j,stencil; 33639accc25SStefano Zampini HYPRE_Complex *values = (HYPRE_Complex*)y; 337f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 338f4bdf6c4SBarry Smith 3394ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 3404ddd07fcSJed Brown PetscInt ordering; 3414ddd07fcSJed Brown PetscInt grid_rank, to_grid_rank; 3424ddd07fcSJed Brown PetscInt var_type, to_var_type; 3434ddd07fcSJed Brown PetscInt to_var_entry = 0; 3444ddd07fcSJed Brown PetscInt nvars= ex->nvars; 3452cf14000SStefano Zampini PetscInt row; 346f4bdf6c4SBarry Smith 347f4bdf6c4SBarry Smith PetscFunctionBegin; 3489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7*nvars,&entries)); 349f4bdf6c4SBarry Smith ordering = ex->dofs_order; /* ordering= 0 nodal ordering 350f4bdf6c4SBarry Smith 1 variable ordering */ 35161710fbeSStefano Zampini /* stencil entries are ordered by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 352f4bdf6c4SBarry Smith if (!ordering) { 353f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 354f4bdf6c4SBarry Smith grid_rank= irow[i]/nvars; 355f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 356f4bdf6c4SBarry Smith 357f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 358f4bdf6c4SBarry Smith to_grid_rank= icol[j]/nvars; 359f4bdf6c4SBarry Smith to_var_type = (icol[j] % nvars); 360f4bdf6c4SBarry Smith 361f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 362f4bdf6c4SBarry Smith entries[j] = to_var_entry; 363f4bdf6c4SBarry Smith 364f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 365f4bdf6c4SBarry Smith if (!stencil) { 366f4bdf6c4SBarry Smith entries[j] += 3; 367f4bdf6c4SBarry Smith } else if (stencil == -1) { 368f4bdf6c4SBarry Smith entries[j] += 2; 369f4bdf6c4SBarry Smith } else if (stencil == 1) { 370f4bdf6c4SBarry Smith entries[j] += 4; 371f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 372f4bdf6c4SBarry Smith entries[j] += 1; 373f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 374f4bdf6c4SBarry Smith entries[j] += 5; 375f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 376f4bdf6c4SBarry Smith entries[j] += 0; 377f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 378f4bdf6c4SBarry Smith entries[j] += 6; 37998921bdaSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 380f4bdf6c4SBarry Smith } 381f4bdf6c4SBarry Smith 382f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 3832cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 3842cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny)); 3852cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny))); 386f4bdf6c4SBarry Smith 387f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 388a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,ex->ss_mat,part,index,var_type,ncol,entries,values); 389f4bdf6c4SBarry Smith } else { 390a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,ncol,entries,values); 391f4bdf6c4SBarry Smith } 392f4bdf6c4SBarry Smith values += ncol; 393f4bdf6c4SBarry Smith } 394f4bdf6c4SBarry Smith } else { 395f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 396f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 397f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 398f4bdf6c4SBarry Smith 399f4bdf6c4SBarry Smith for (j=0; j<ncol; j++) { 400f4bdf6c4SBarry Smith to_var_type = icol[j]/(ex->gnxgnygnz); 401f4bdf6c4SBarry Smith to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz); 402f4bdf6c4SBarry Smith 403f4bdf6c4SBarry Smith to_var_entry= to_var_entry*7; 404f4bdf6c4SBarry Smith entries[j] = to_var_entry; 405f4bdf6c4SBarry Smith 406f4bdf6c4SBarry Smith stencil = to_grid_rank-grid_rank; 407f4bdf6c4SBarry Smith if (!stencil) { 408f4bdf6c4SBarry Smith entries[j] += 3; 409f4bdf6c4SBarry Smith } else if (stencil == -1) { 410f4bdf6c4SBarry Smith entries[j] += 2; 411f4bdf6c4SBarry Smith } else if (stencil == 1) { 412f4bdf6c4SBarry Smith entries[j] += 4; 413f4bdf6c4SBarry Smith } else if (stencil == -ex->gnx) { 414f4bdf6c4SBarry Smith entries[j] += 1; 415f4bdf6c4SBarry Smith } else if (stencil == ex->gnx) { 416f4bdf6c4SBarry Smith entries[j] += 5; 417f4bdf6c4SBarry Smith } else if (stencil == -ex->gnxgny) { 418f4bdf6c4SBarry Smith entries[j] += 0; 419f4bdf6c4SBarry Smith } else if (stencil == ex->gnxgny) { 420f4bdf6c4SBarry Smith entries[j] += 6; 42198921bdaSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 422f4bdf6c4SBarry Smith } 423f4bdf6c4SBarry Smith 424f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4252cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4262cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny)); 4272cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny))); 428f4bdf6c4SBarry Smith 429f4bdf6c4SBarry Smith if (addv == ADD_VALUES) { 430a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,ex->ss_mat,part,index,var_type,ncol,entries,values); 431f4bdf6c4SBarry Smith } else { 432a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,ncol,entries,values); 433f4bdf6c4SBarry Smith } 434f4bdf6c4SBarry Smith values += ncol; 435f4bdf6c4SBarry Smith } 436f4bdf6c4SBarry Smith } 4379566063dSJacob Faibussowitsch PetscCall(PetscFree(entries)); 438f4bdf6c4SBarry Smith PetscFunctionReturn(0); 439f4bdf6c4SBarry Smith } 440f4bdf6c4SBarry Smith 441f4bdf6c4SBarry Smith PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 442f4bdf6c4SBarry Smith { 4432cf14000SStefano Zampini HYPRE_Int index[3],*entries; 4442cf14000SStefano Zampini PetscInt i; 44539accc25SStefano Zampini HYPRE_Complex **values; 446f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 447f4bdf6c4SBarry Smith 4484ddd07fcSJed Brown PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 4494ddd07fcSJed Brown PetscInt ordering = ex->dofs_order; 4504ddd07fcSJed Brown PetscInt grid_rank; 4514ddd07fcSJed Brown PetscInt var_type; 4524ddd07fcSJed Brown PetscInt nvars= ex->nvars; 4532cf14000SStefano Zampini PetscInt row; 454f4bdf6c4SBarry Smith 455f4bdf6c4SBarry Smith PetscFunctionBegin; 456*08401ef6SPierre Jolivet PetscCheck(!x || !b,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 4579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7*nvars,&entries)); 458f4bdf6c4SBarry Smith 4599566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nvars,&values)); 4609566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(7*nvars*nvars,&values[0])); 461f4bdf6c4SBarry Smith for (i=1; i<nvars; i++) { 462f4bdf6c4SBarry Smith values[i] = values[i-1] + nvars*7; 463f4bdf6c4SBarry Smith } 464f4bdf6c4SBarry Smith 465f4bdf6c4SBarry Smith for (i=0; i< nvars; i++) { 4669566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values[i],nvars*7*sizeof(HYPRE_Complex))); 4679566063dSJacob Faibussowitsch PetscCall(PetscHYPREScalarCast(d,values[i]+3)); 468f4bdf6c4SBarry Smith } 469f4bdf6c4SBarry Smith 4708865f1eaSKarl Rupp for (i=0; i< nvars*7; i++) entries[i] = i; 471f4bdf6c4SBarry Smith 472f4bdf6c4SBarry Smith if (!ordering) { 473f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 474f4bdf6c4SBarry Smith grid_rank = irow[i] / nvars; 475f4bdf6c4SBarry Smith var_type = (irow[i] % nvars); 476f4bdf6c4SBarry Smith 477f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4782cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4792cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny)); 4802cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny))); 481a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]); 482f4bdf6c4SBarry Smith } 483f4bdf6c4SBarry Smith } else { 484f4bdf6c4SBarry Smith for (i=0; i<nrow; i++) { 485f4bdf6c4SBarry Smith var_type = irow[i]/(ex->gnxgnygnz); 486f4bdf6c4SBarry Smith grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 487f4bdf6c4SBarry Smith 488f4bdf6c4SBarry Smith row = ex->gindices[grid_rank] - ex->rstart; 4892cf14000SStefano Zampini index[0] = (HYPRE_Int)(ex->xs + (row % ex->nx)); 4902cf14000SStefano Zampini index[1] = (HYPRE_Int)(ex->ys + ((row/ex->nx) % ex->ny)); 4912cf14000SStefano Zampini index[2] = (HYPRE_Int)(ex->zs + (row/(ex->nxny))); 492a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixSetValues,ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type]); 493f4bdf6c4SBarry Smith } 494f4bdf6c4SBarry Smith } 495a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat); 4969566063dSJacob Faibussowitsch PetscCall(PetscFree(values[0])); 4979566063dSJacob Faibussowitsch PetscCall(PetscFree(values)); 4989566063dSJacob Faibussowitsch PetscCall(PetscFree(entries)); 499f4bdf6c4SBarry Smith PetscFunctionReturn(0); 500f4bdf6c4SBarry Smith } 501f4bdf6c4SBarry Smith 502f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 503f4bdf6c4SBarry Smith { 504f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 5054ddd07fcSJed Brown PetscInt nvars= ex->nvars; 5064ddd07fcSJed Brown PetscInt size; 5074ddd07fcSJed Brown PetscInt part= 0; /* only one part */ 508f4bdf6c4SBarry Smith 509f4bdf6c4SBarry Smith PetscFunctionBegin; 510f4bdf6c4SBarry 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); 511f4bdf6c4SBarry Smith { 5122cf14000SStefano Zampini HYPRE_Int i,*entries,iupper[3],ilower[3]; 51339accc25SStefano Zampini HYPRE_Complex *values; 5144ddd07fcSJed Brown 515f4bdf6c4SBarry Smith for (i= 0; i< 3; i++) { 516f4bdf6c4SBarry Smith ilower[i] = ex->hbox.imin[i]; 517f4bdf6c4SBarry Smith iupper[i] = ex->hbox.imax[i]; 518f4bdf6c4SBarry Smith } 519f4bdf6c4SBarry Smith 5209566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nvars*7,&entries,nvars*7*size,&values)); 5218865f1eaSKarl Rupp for (i= 0; i< nvars*7; i++) entries[i] = i; 5229566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(values,nvars*7*size)); 523f4bdf6c4SBarry Smith 524f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 525a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values); 526f4bdf6c4SBarry Smith } 5279566063dSJacob Faibussowitsch PetscCall(PetscFree2(entries,values)); 528f4bdf6c4SBarry Smith } 529a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat); 530f4bdf6c4SBarry Smith PetscFunctionReturn(0); 531f4bdf6c4SBarry Smith } 532f4bdf6c4SBarry Smith 53359cb773eSBarry Smith static PetscErrorCode MatSetUp_HYPRESStruct(Mat mat) 534f4bdf6c4SBarry Smith { 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 */ 5692c71b3e2SJacob Faibussowitsch PetscCheckFalse(px || py || pz,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 570a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGridCreate,ex->hcomm,dim,nparts,&ex->ss_grid); 571a74df02fSJacob Faibussowitsch PetscStackCallStandard(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; 576a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGridSetVariables,ex->ss_grid, part, ex->nvars,vartypes); 5779566063dSJacob Faibussowitsch PetscCall(PetscFree(vartypes)); 578f4bdf6c4SBarry Smith } 579a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGridAssemble,ex->ss_grid); 580f4bdf6c4SBarry Smith 581f4bdf6c4SBarry Smith sw[1] = sw[0]; 582f4bdf6c4SBarry Smith sw[2] = sw[1]; 583a74df02fSJacob Faibussowitsch /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,ex->ss_grid,sw); */ 584f4bdf6c4SBarry Smith 585f4bdf6c4SBarry Smith /* create the hypre stencil object and set its information */ 586*08401ef6SPierre Jolivet PetscCheck(sw[0] <= 1,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 587*08401ef6SPierre 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); 594a74df02fSJacob Faibussowitsch PetscStackCallStandard(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++) { 598a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i); 599f4bdf6c4SBarry Smith cnt++; 600f4bdf6c4SBarry Smith } 601f4bdf6c4SBarry Smith } 602f4bdf6c4SBarry Smith } else if (dim == 2) { 6032cf14000SStefano Zampini HYPRE_Int offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 6044ddd07fcSJed Brown PetscInt j, cnt; 605f4bdf6c4SBarry Smith 606f4bdf6c4SBarry Smith ssize = 5*(ex->nvars); 607a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilCreate,dim,ssize,&ex->ss_stencil); 608f4bdf6c4SBarry Smith cnt= 0; 609f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 610f4bdf6c4SBarry Smith for (j= 0; j< 5; j++) { 611a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i); 612f4bdf6c4SBarry Smith cnt++; 613f4bdf6c4SBarry Smith } 614f4bdf6c4SBarry Smith } 615f4bdf6c4SBarry Smith } else if (dim == 3) { 6162cf14000SStefano Zampini HYPRE_Int offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; 6174ddd07fcSJed Brown PetscInt j, cnt; 618f4bdf6c4SBarry Smith 619f4bdf6c4SBarry Smith ssize = 7*(ex->nvars); 620a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilCreate,dim,ssize,&ex->ss_stencil); 621f4bdf6c4SBarry Smith cnt= 0; 622f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 623f4bdf6c4SBarry Smith for (j= 0; j< 7; j++) { 624a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilSetEntry,ex->ss_stencil, cnt, offsets[j], i); 625f4bdf6c4SBarry Smith cnt++; 626f4bdf6c4SBarry Smith } 627f4bdf6c4SBarry Smith } 628f4bdf6c4SBarry Smith } 629f4bdf6c4SBarry Smith 630f4bdf6c4SBarry Smith /* create the HYPRE graph */ 631a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGraphCreate,ex->hcomm, ex->ss_grid, &(ex->ss_graph)); 632f4bdf6c4SBarry Smith 633f4bdf6c4SBarry Smith /* set the stencil graph. Note that each variable has the same graph. This means that each 634f4bdf6c4SBarry Smith variable couples to all the other variable and with the same stencil pattern. */ 635f4bdf6c4SBarry Smith for (i= 0; i< (ex->nvars); i++) { 636a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGraphSetStencil,ex->ss_graph,part,i,ex->ss_stencil); 637f4bdf6c4SBarry Smith } 638a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGraphAssemble,ex->ss_graph); 639f4bdf6c4SBarry Smith 640f4bdf6c4SBarry Smith /* create the HYPRE sstruct vectors for rhs and solution */ 641a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorCreate,ex->hcomm,ex->ss_grid,&ex->ss_b); 642a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorCreate,ex->hcomm,ex->ss_grid,&ex->ss_x); 643a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorInitialize,ex->ss_b); 644a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorInitialize,ex->ss_x); 645a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorAssemble,ex->ss_b); 646a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorAssemble,ex->ss_x); 647f4bdf6c4SBarry Smith 648f4bdf6c4SBarry Smith /* create the hypre matrix object and set its information */ 649a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixCreate,ex->hcomm,ex->ss_graph,&ex->ss_mat); 650a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGridDestroy,ex->ss_grid); 651a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructStencilDestroy,ex->ss_stencil); 652f4bdf6c4SBarry Smith if (ex->needsinitialization) { 653a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixInitialize,ex->ss_mat); 654f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_FALSE; 655f4bdf6c4SBarry Smith } 656f4bdf6c4SBarry Smith 657f4bdf6c4SBarry Smith /* set the global and local sizes of the matrix */ 6589566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da,0,0,0,&nx,&ny,&nz)); 6599566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE)); 6609566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->rmap,dof)); 6619566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(mat->cmap,dof)); 6629566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->rmap)); 6639566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(mat->cmap)); 66461710fbeSStefano Zampini mat->preallocated = PETSC_TRUE; 665f4bdf6c4SBarry Smith 666f4bdf6c4SBarry Smith if (dim == 3) { 667f4bdf6c4SBarry Smith mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 668f4bdf6c4SBarry Smith mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 669f4bdf6c4SBarry Smith mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 6708865f1eaSKarl Rupp 6719566063dSJacob Faibussowitsch /* PetscCall(MatZeroEntries_HYPRESStruct_3d(mat)); */ 672ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 673f4bdf6c4SBarry Smith 674f4bdf6c4SBarry Smith /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 6759566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat,&ex->rstart,NULL)); 6769566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da,<og)); 6779566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices)); 6789566063dSJacob Faibussowitsch PetscCall(DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz)); 6798865f1eaSKarl Rupp 680f4bdf6c4SBarry Smith ex->gnxgny *= ex->gnx; 681f4bdf6c4SBarry Smith ex->gnxgnygnz *= ex->gnxgny; 6828865f1eaSKarl Rupp 6839566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz)); 6848865f1eaSKarl Rupp 685f4bdf6c4SBarry Smith ex->nxny = ex->nx*ex->ny; 686f4bdf6c4SBarry Smith ex->nxnynz = ex->nz*ex->nxny; 687f4bdf6c4SBarry Smith PetscFunctionReturn(0); 688f4bdf6c4SBarry Smith } 689f4bdf6c4SBarry Smith 690f4bdf6c4SBarry Smith PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y) 691f4bdf6c4SBarry Smith { 692b026d285SBarry Smith const PetscScalar *xx; 693b026d285SBarry Smith PetscScalar *yy; 6942cf14000SStefano Zampini HYPRE_Int hlower[3],hupper[3]; 6954ddd07fcSJed Brown PetscInt ilower[3],iupper[3]; 696f4bdf6c4SBarry Smith Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(A->data); 6974ddd07fcSJed Brown PetscInt ordering= mx->dofs_order; 6984ddd07fcSJed Brown PetscInt nvars = mx->nvars; 6994ddd07fcSJed Brown PetscInt part = 0; 7004ddd07fcSJed Brown PetscInt size; 7014ddd07fcSJed Brown PetscInt i; 702f4bdf6c4SBarry Smith 703f4bdf6c4SBarry Smith PetscFunctionBegin; 7049566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2])); 7052cf14000SStefano Zampini 7062cf14000SStefano Zampini /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */ 707f4bdf6c4SBarry Smith iupper[0] += ilower[0] - 1; 708f4bdf6c4SBarry Smith iupper[1] += ilower[1] - 1; 709f4bdf6c4SBarry Smith iupper[2] += ilower[2] - 1; 7102cf14000SStefano Zampini hlower[0] = (HYPRE_Int)ilower[0]; 7112cf14000SStefano Zampini hlower[1] = (HYPRE_Int)ilower[1]; 7122cf14000SStefano Zampini hlower[2] = (HYPRE_Int)ilower[2]; 7132cf14000SStefano Zampini hupper[0] = (HYPRE_Int)iupper[0]; 7142cf14000SStefano Zampini hupper[1] = (HYPRE_Int)iupper[1]; 7152cf14000SStefano Zampini hupper[2] = (HYPRE_Int)iupper[2]; 716f4bdf6c4SBarry Smith 717f4bdf6c4SBarry Smith size= 1; 7188865f1eaSKarl Rupp for (i = 0; i < 3; i++) size *= (iupper[i]-ilower[i]+1); 719f4bdf6c4SBarry Smith 720f4bdf6c4SBarry Smith /* copy x values over to hypre for variable ordering */ 721f4bdf6c4SBarry Smith if (ordering) { 722a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0); 7239566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x,&xx)); 724f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 725a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(xx+(size*i))); 726f4bdf6c4SBarry Smith } 7279566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x,&xx)); 728a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b); 729a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x); 730f4bdf6c4SBarry Smith 731f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 7329566063dSJacob Faibussowitsch PetscCall(VecGetArray(y,&yy)); 733f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 734a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(yy+(size*i))); 735f4bdf6c4SBarry Smith } 7369566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y,&yy)); 737f4bdf6c4SBarry Smith } else { /* nodal ordering must be mapped to variable ordering for sys_pfmg */ 738f4bdf6c4SBarry Smith PetscScalar *z; 7394ddd07fcSJed Brown PetscInt j, k; 740f4bdf6c4SBarry Smith 7419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nvars*size,&z)); 742a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0); 7439566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x,&xx)); 744f4bdf6c4SBarry Smith 745f4bdf6c4SBarry Smith /* transform nodal to hypre's variable ordering for sys_pfmg */ 746f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 747f4bdf6c4SBarry Smith k= i*nvars; 7488865f1eaSKarl Rupp for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j]; 749f4bdf6c4SBarry Smith } 750f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 751a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i))); 752f4bdf6c4SBarry Smith } 7539566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x,&xx)); 754a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b); 755a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x); 756f4bdf6c4SBarry Smith 757f4bdf6c4SBarry Smith /* copy solution values back to PETSc */ 7589566063dSJacob Faibussowitsch PetscCall(VecGetArray(y,&yy)); 759f4bdf6c4SBarry Smith for (i= 0; i< nvars; i++) { 760a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i))); 761f4bdf6c4SBarry Smith } 762f4bdf6c4SBarry Smith /* transform hypre's variable ordering for sys_pfmg to nodal ordering */ 763f4bdf6c4SBarry Smith for (i= 0; i< size; i++) { 764f4bdf6c4SBarry Smith k= i*nvars; 7658865f1eaSKarl Rupp for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i]; 766f4bdf6c4SBarry Smith } 7679566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y,&yy)); 7689566063dSJacob Faibussowitsch PetscCall(PetscFree(z)); 769f4bdf6c4SBarry Smith } 770f4bdf6c4SBarry Smith PetscFunctionReturn(0); 771f4bdf6c4SBarry Smith } 772f4bdf6c4SBarry Smith 773f4bdf6c4SBarry Smith PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode) 774f4bdf6c4SBarry Smith { 775f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 776f4bdf6c4SBarry Smith 777f4bdf6c4SBarry Smith PetscFunctionBegin; 778a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixAssemble,ex->ss_mat); 779f4bdf6c4SBarry Smith PetscFunctionReturn(0); 780f4bdf6c4SBarry Smith } 781f4bdf6c4SBarry Smith 782f4bdf6c4SBarry Smith PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat) 783f4bdf6c4SBarry Smith { 784f4bdf6c4SBarry Smith PetscFunctionBegin; 785f4bdf6c4SBarry Smith /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 786f4bdf6c4SBarry Smith PetscFunctionReturn(0); 787f4bdf6c4SBarry Smith } 788f4bdf6c4SBarry Smith 789f4bdf6c4SBarry Smith PetscErrorCode MatDestroy_HYPRESStruct(Mat mat) 790f4bdf6c4SBarry Smith { 791f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 792d94fc0b6SBarry Smith ISLocalToGlobalMapping ltog; 793f4bdf6c4SBarry Smith 794f4bdf6c4SBarry Smith PetscFunctionBegin; 7959566063dSJacob Faibussowitsch PetscCall(DMGetLocalToGlobalMapping(ex->da,<og)); 7969566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingRestoreIndices(ltog, (const PetscInt **) &ex->gindices)); 797a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructGraphDestroy,ex->ss_graph); 798a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructMatrixDestroy,ex->ss_mat); 799a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorDestroy,ex->ss_x); 800a74df02fSJacob Faibussowitsch PetscStackCallStandard(HYPRE_SStructVectorDestroy,ex->ss_b); 8019566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)ex->da)); 8029566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_free(&(ex->hcomm))); 8039566063dSJacob Faibussowitsch PetscCall(PetscFree(ex)); 804f4bdf6c4SBarry Smith PetscFunctionReturn(0); 805f4bdf6c4SBarry Smith } 806f4bdf6c4SBarry Smith 8078cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B) 808f4bdf6c4SBarry Smith { 809f4bdf6c4SBarry Smith Mat_HYPRESStruct *ex; 810f4bdf6c4SBarry Smith 811f4bdf6c4SBarry Smith PetscFunctionBegin; 8129566063dSJacob Faibussowitsch PetscCall(PetscNewLog(B,&ex)); 813f4bdf6c4SBarry Smith B->data = (void*)ex; 814f4bdf6c4SBarry Smith B->rmap->bs = 1; 815f4bdf6c4SBarry Smith B->assembled = PETSC_FALSE; 816f4bdf6c4SBarry Smith 817f4bdf6c4SBarry Smith B->insertmode = NOT_SET_VALUES; 818f4bdf6c4SBarry Smith 819f4bdf6c4SBarry Smith B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 820f4bdf6c4SBarry Smith B->ops->mult = MatMult_HYPRESStruct; 821f4bdf6c4SBarry Smith B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 822f4bdf6c4SBarry Smith B->ops->destroy = MatDestroy_HYPRESStruct; 82359cb773eSBarry Smith B->ops->setup = MatSetUp_HYPRESStruct; 824f4bdf6c4SBarry Smith 825f4bdf6c4SBarry Smith ex->needsinitialization = PETSC_TRUE; 826f4bdf6c4SBarry Smith 8279566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm))); 8289566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT)); 829f4bdf6c4SBarry Smith PetscFunctionReturn(0); 830f4bdf6c4SBarry Smith } 831