1dba47a55SKris Buschelman 24b9ad928SBarry Smith /* 34b9ad928SBarry Smith Defines a preconditioner that can consist of a collection of PCs 44b9ad928SBarry Smith */ 5af0996ceSBarry Smith #include <petsc/private/pcimpl.h> 6c6db04a5SJed Brown #include <petscksp.h> /*I "petscksp.h" I*/ 74b9ad928SBarry Smith 84b9ad928SBarry Smith typedef struct _PC_CompositeLink *PC_CompositeLink; 94b9ad928SBarry Smith struct _PC_CompositeLink { 104b9ad928SBarry Smith PC pc; 114b9ad928SBarry Smith PC_CompositeLink next; 12421e10b8SBarry Smith PC_CompositeLink previous; 134b9ad928SBarry Smith }; 144b9ad928SBarry Smith 154b9ad928SBarry Smith typedef struct { 164b9ad928SBarry Smith PC_CompositeLink head; 174b9ad928SBarry Smith PCCompositeType type; 184b9ad928SBarry Smith Vec work1; 194b9ad928SBarry Smith Vec work2; 204b9ad928SBarry Smith PetscScalar alpha; 214b9ad928SBarry Smith } PC_Composite; 224b9ad928SBarry Smith 234b9ad928SBarry Smith #undef __FUNCT__ 244b9ad928SBarry Smith #define __FUNCT__ "PCApply_Composite_Multiplicative" 256849ba73SBarry Smith static PetscErrorCode PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y) 264b9ad928SBarry Smith { 27dfbe8321SBarry Smith PetscErrorCode ierr; 284b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 294b9ad928SBarry Smith PC_CompositeLink next = jac->head; 304b9ad928SBarry Smith Mat mat = pc->pmat; 314b9ad928SBarry Smith 324b9ad928SBarry Smith PetscFunctionBegin; 33450d59ebSPatrick Farrell 34ce94432eSBarry Smith if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs"); 35450d59ebSPatrick Farrell 36450d59ebSPatrick Farrell /* Set the reuse flag on children PCs */ 37450d59ebSPatrick Farrell while (next) { 38450d59ebSPatrick Farrell ierr = PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);CHKERRQ(ierr); 39450d59ebSPatrick Farrell next = next->next; 40450d59ebSPatrick Farrell } 41450d59ebSPatrick Farrell next = jac->head; 42450d59ebSPatrick Farrell 434b9ad928SBarry Smith if (next->next && !jac->work2) { /* allocate second work vector */ 444b9ad928SBarry Smith ierr = VecDuplicate(jac->work1,&jac->work2);CHKERRQ(ierr); 454b9ad928SBarry Smith } 4649517cdeSBarry Smith if (pc->useAmat) mat = pc->mat; 4709b21952SJed Brown ierr = PCApply(next->pc,x,y);CHKERRQ(ierr); /* y <- B x */ 484b9ad928SBarry Smith while (next->next) { 494b9ad928SBarry Smith next = next->next; 5009b21952SJed Brown ierr = MatMult(mat,y,jac->work1);CHKERRQ(ierr); /* work1 <- A y */ 5109b21952SJed Brown ierr = VecWAXPY(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr); /* work2 <- x - work1 */ 5251f519a2SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 5309b21952SJed Brown ierr = PCApply(next->pc,jac->work2,jac->work1);CHKERRQ(ierr); /* work1 <- C work2 */ 5409b21952SJed Brown ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); /* y <- y + work1 = B x + C (x - A B x) = (B + C (1 - A B)) x */ 554b9ad928SBarry Smith } 56421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 57421e10b8SBarry Smith while (next->previous) { 58421e10b8SBarry Smith next = next->previous; 59421e10b8SBarry Smith ierr = MatMult(mat,y,jac->work1);CHKERRQ(ierr); 60421e10b8SBarry Smith ierr = VecWAXPY(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr); 61421e10b8SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 62421e10b8SBarry Smith ierr = PCApply(next->pc,jac->work2,jac->work1);CHKERRQ(ierr); 63421e10b8SBarry Smith ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); 64421e10b8SBarry Smith } 65421e10b8SBarry Smith } 664b9ad928SBarry Smith PetscFunctionReturn(0); 674b9ad928SBarry Smith } 684b9ad928SBarry Smith 692533e041SBarry Smith #undef __FUNCT__ 702533e041SBarry Smith #define __FUNCT__ "PCApplyTranspose_Composite_Multiplicative" 712533e041SBarry Smith static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc,Vec x,Vec y) 722533e041SBarry Smith { 732533e041SBarry Smith PetscErrorCode ierr; 742533e041SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 752533e041SBarry Smith PC_CompositeLink next = jac->head; 762533e041SBarry Smith Mat mat = pc->pmat; 772533e041SBarry Smith 782533e041SBarry Smith PetscFunctionBegin; 79ce94432eSBarry Smith if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs"); 802533e041SBarry Smith if (next->next && !jac->work2) { /* allocate second work vector */ 812533e041SBarry Smith ierr = VecDuplicate(jac->work1,&jac->work2);CHKERRQ(ierr); 822533e041SBarry Smith } 8349517cdeSBarry Smith if (pc->useAmat) mat = pc->mat; 842533e041SBarry Smith /* locate last PC */ 852533e041SBarry Smith while (next->next) { 862533e041SBarry Smith next = next->next; 872533e041SBarry Smith } 882533e041SBarry Smith ierr = PCApplyTranspose(next->pc,x,y);CHKERRQ(ierr); 892533e041SBarry Smith while (next->previous) { 902533e041SBarry Smith next = next->previous; 912533e041SBarry Smith ierr = MatMultTranspose(mat,y,jac->work1);CHKERRQ(ierr); 922533e041SBarry Smith ierr = VecWAXPY(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr); 932533e041SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 942533e041SBarry Smith ierr = PCApplyTranspose(next->pc,jac->work2,jac->work1);CHKERRQ(ierr); 952533e041SBarry Smith ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); 962533e041SBarry Smith } 972533e041SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 982533e041SBarry Smith next = jac->head; 992533e041SBarry Smith while (next->next) { 1002533e041SBarry Smith next = next->next; 1012533e041SBarry Smith ierr = MatMultTranspose(mat,y,jac->work1);CHKERRQ(ierr); 1022533e041SBarry Smith ierr = VecWAXPY(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr); 1032533e041SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 1042533e041SBarry Smith ierr = PCApplyTranspose(next->pc,jac->work2,jac->work1);CHKERRQ(ierr); 1052533e041SBarry Smith ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); 1062533e041SBarry Smith } 1072533e041SBarry Smith } 1082533e041SBarry Smith PetscFunctionReturn(0); 1092533e041SBarry Smith } 1102533e041SBarry Smith 1114b9ad928SBarry Smith /* 1124b9ad928SBarry Smith This is very special for a matrix of the form alpha I + R + S 1134b9ad928SBarry Smith where first preconditioner is built from alpha I + S and second from 1144b9ad928SBarry Smith alpha I + R 1154b9ad928SBarry Smith */ 1164b9ad928SBarry Smith #undef __FUNCT__ 1174b9ad928SBarry Smith #define __FUNCT__ "PCApply_Composite_Special" 1186849ba73SBarry Smith static PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y) 1194b9ad928SBarry Smith { 120dfbe8321SBarry Smith PetscErrorCode ierr; 1214b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 1224b9ad928SBarry Smith PC_CompositeLink next = jac->head; 1234b9ad928SBarry Smith 1244b9ad928SBarry Smith PetscFunctionBegin; 125ce94432eSBarry Smith if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs"); 126ce94432eSBarry Smith if (!next->next || next->next->next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Special composite preconditioners requires exactly two PCs"); 1274b9ad928SBarry Smith 128450d59ebSPatrick Farrell /* Set the reuse flag on children PCs */ 129450d59ebSPatrick Farrell ierr = PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);CHKERRQ(ierr); 130450d59ebSPatrick Farrell ierr = PCSetReusePreconditioner(next->next->pc,pc->reusepreconditioner);CHKERRQ(ierr); 131450d59ebSPatrick Farrell 132d8fd42c4SBarry Smith ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr); 133d8fd42c4SBarry Smith ierr = PCApply(next->next->pc,jac->work1,y);CHKERRQ(ierr); 1344b9ad928SBarry Smith PetscFunctionReturn(0); 1354b9ad928SBarry Smith } 1364b9ad928SBarry Smith 1374b9ad928SBarry Smith #undef __FUNCT__ 1384b9ad928SBarry Smith #define __FUNCT__ "PCApply_Composite_Additive" 1396849ba73SBarry Smith static PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y) 1404b9ad928SBarry Smith { 141dfbe8321SBarry Smith PetscErrorCode ierr; 1424b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 1434b9ad928SBarry Smith PC_CompositeLink next = jac->head; 1444b9ad928SBarry Smith 1454b9ad928SBarry Smith PetscFunctionBegin; 146ce94432eSBarry Smith if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs"); 147450d59ebSPatrick Farrell 148450d59ebSPatrick Farrell /* Set the reuse flag on children PCs */ 149450d59ebSPatrick Farrell while (next) { 150450d59ebSPatrick Farrell ierr = PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);CHKERRQ(ierr); 151450d59ebSPatrick Farrell next = next->next; 152450d59ebSPatrick Farrell } 153450d59ebSPatrick Farrell next = jac->head; 154450d59ebSPatrick Farrell 155d8fd42c4SBarry Smith ierr = PCApply(next->pc,x,y);CHKERRQ(ierr); 1564b9ad928SBarry Smith while (next->next) { 1574b9ad928SBarry Smith next = next->next; 15851f519a2SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 159d8fd42c4SBarry Smith ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr); 160efb30889SBarry Smith ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); 1614b9ad928SBarry Smith } 1624b9ad928SBarry Smith PetscFunctionReturn(0); 1634b9ad928SBarry Smith } 1644b9ad928SBarry Smith 1654b9ad928SBarry Smith #undef __FUNCT__ 1662533e041SBarry Smith #define __FUNCT__ "PCApplyTranspose_Composite_Additive" 1672533e041SBarry Smith static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc,Vec x,Vec y) 1682533e041SBarry Smith { 1692533e041SBarry Smith PetscErrorCode ierr; 1702533e041SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 1712533e041SBarry Smith PC_CompositeLink next = jac->head; 1722533e041SBarry Smith 1732533e041SBarry Smith PetscFunctionBegin; 174ce94432eSBarry Smith if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs"); 1752533e041SBarry Smith ierr = PCApplyTranspose(next->pc,x,y);CHKERRQ(ierr); 1762533e041SBarry Smith while (next->next) { 1772533e041SBarry Smith next = next->next; 1782533e041SBarry Smith ierr = VecSet(jac->work1,0.0);CHKERRQ(ierr); /* zero since some PC's may not set all entries in the result */ 1792533e041SBarry Smith ierr = PCApplyTranspose(next->pc,x,jac->work1);CHKERRQ(ierr); 1802533e041SBarry Smith ierr = VecAXPY(y,1.0,jac->work1);CHKERRQ(ierr); 1812533e041SBarry Smith } 1822533e041SBarry Smith PetscFunctionReturn(0); 1832533e041SBarry Smith } 1842533e041SBarry Smith 1852533e041SBarry Smith #undef __FUNCT__ 1864b9ad928SBarry Smith #define __FUNCT__ "PCSetUp_Composite" 1876849ba73SBarry Smith static PetscErrorCode PCSetUp_Composite(PC pc) 1884b9ad928SBarry Smith { 189dfbe8321SBarry Smith PetscErrorCode ierr; 1904b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 1914b9ad928SBarry Smith PC_CompositeLink next = jac->head; 1925a78d018SMatthew G. Knepley DM dm; 1934b9ad928SBarry Smith 1944b9ad928SBarry Smith PetscFunctionBegin; 1954b9ad928SBarry Smith if (!jac->work1) { 1962a7a6963SBarry Smith ierr = MatCreateVecs(pc->pmat,&jac->work1,0);CHKERRQ(ierr); 1974b9ad928SBarry Smith } 1985a78d018SMatthew G. Knepley ierr = PCGetDM(pc,&dm);CHKERRQ(ierr); 1994b9ad928SBarry Smith while (next) { 2005a78d018SMatthew G. Knepley ierr = PCSetDM(next->pc,dm);CHKERRQ(ierr); 20123ee1639SBarry Smith ierr = PCSetOperators(next->pc,pc->mat,pc->pmat);CHKERRQ(ierr); 2024b9ad928SBarry Smith next = next->next; 2034b9ad928SBarry Smith } 2044b9ad928SBarry Smith PetscFunctionReturn(0); 2054b9ad928SBarry Smith } 2064b9ad928SBarry Smith 2074b9ad928SBarry Smith #undef __FUNCT__ 20869d2c0f9SBarry Smith #define __FUNCT__ "PCReset_Composite" 20969d2c0f9SBarry Smith static PetscErrorCode PCReset_Composite(PC pc) 21069d2c0f9SBarry Smith { 21169d2c0f9SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 21269d2c0f9SBarry Smith PetscErrorCode ierr; 2135f48b12bSBarry Smith PC_CompositeLink next = jac->head; 21469d2c0f9SBarry Smith 21569d2c0f9SBarry Smith PetscFunctionBegin; 21669d2c0f9SBarry Smith while (next) { 21769d2c0f9SBarry Smith ierr = PCReset(next->pc);CHKERRQ(ierr); 21869d2c0f9SBarry Smith next = next->next; 21969d2c0f9SBarry Smith } 2206bf464f9SBarry Smith ierr = VecDestroy(&jac->work1);CHKERRQ(ierr); 2216bf464f9SBarry Smith ierr = VecDestroy(&jac->work2);CHKERRQ(ierr); 22269d2c0f9SBarry Smith PetscFunctionReturn(0); 22369d2c0f9SBarry Smith } 22469d2c0f9SBarry Smith 22569d2c0f9SBarry Smith #undef __FUNCT__ 2264b9ad928SBarry Smith #define __FUNCT__ "PCDestroy_Composite" 2276849ba73SBarry Smith static PetscErrorCode PCDestroy_Composite(PC pc) 2284b9ad928SBarry Smith { 2294b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 230dfbe8321SBarry Smith PetscErrorCode ierr; 231724c2c99SHong Zhang PC_CompositeLink next = jac->head,next_tmp; 2324b9ad928SBarry Smith 2334b9ad928SBarry Smith PetscFunctionBegin; 23469d2c0f9SBarry Smith ierr = PCReset_Composite(pc);CHKERRQ(ierr); 2354b9ad928SBarry Smith while (next) { 2366bf464f9SBarry Smith ierr = PCDestroy(&next->pc);CHKERRQ(ierr); 237724c2c99SHong Zhang next_tmp = next; 2384b9ad928SBarry Smith next = next->next; 239724c2c99SHong Zhang ierr = PetscFree(next_tmp);CHKERRQ(ierr); 2404b9ad928SBarry Smith } 241c31cb41cSBarry Smith ierr = PetscFree(pc->data);CHKERRQ(ierr); 2424b9ad928SBarry Smith PetscFunctionReturn(0); 2434b9ad928SBarry Smith } 2444b9ad928SBarry Smith 2454b9ad928SBarry Smith #undef __FUNCT__ 2464b9ad928SBarry Smith #define __FUNCT__ "PCSetFromOptions_Composite" 247*4416b707SBarry Smith static PetscErrorCode PCSetFromOptions_Composite(PetscOptionItems *PetscOptionsObject,PC pc) 2484b9ad928SBarry Smith { 2494b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 250dfbe8321SBarry Smith PetscErrorCode ierr; 2519dcbbd2bSBarry Smith PetscInt nmax = 8,i; 2524b9ad928SBarry Smith PC_CompositeLink next; 253e5999256SBarry Smith char *pcs[8]; 254ace3abfcSBarry Smith PetscBool flg; 2554b9ad928SBarry Smith 2564b9ad928SBarry Smith PetscFunctionBegin; 257e55864a3SBarry Smith ierr = PetscOptionsHead(PetscOptionsObject,"Composite preconditioner options");CHKERRQ(ierr); 2589dcbbd2bSBarry Smith ierr = PetscOptionsEnum("-pc_composite_type","Type of composition","PCCompositeSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);CHKERRQ(ierr); 25951f519a2SBarry Smith if (flg) { 26051f519a2SBarry Smith ierr = PCCompositeSetType(pc,jac->type);CHKERRQ(ierr); 26151f519a2SBarry Smith } 2624b9ad928SBarry Smith ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr); 2634b9ad928SBarry Smith if (flg) { 2644b9ad928SBarry Smith for (i=0; i<nmax; i++) { 2654b9ad928SBarry Smith ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr); 266724c2c99SHong Zhang ierr = PetscFree(pcs[i]);CHKERRQ(ierr); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */ 2674b9ad928SBarry Smith } 2684b9ad928SBarry Smith } 2694b9ad928SBarry Smith ierr = PetscOptionsTail();CHKERRQ(ierr); 2704b9ad928SBarry Smith 2714b9ad928SBarry Smith next = jac->head; 2724b9ad928SBarry Smith while (next) { 2734b9ad928SBarry Smith ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr); 2744b9ad928SBarry Smith next = next->next; 2754b9ad928SBarry Smith } 2764b9ad928SBarry Smith PetscFunctionReturn(0); 2774b9ad928SBarry Smith } 2784b9ad928SBarry Smith 2794b9ad928SBarry Smith #undef __FUNCT__ 2804b9ad928SBarry Smith #define __FUNCT__ "PCView_Composite" 2816849ba73SBarry Smith static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer) 2824b9ad928SBarry Smith { 2834b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 284dfbe8321SBarry Smith PetscErrorCode ierr; 2854b9ad928SBarry Smith PC_CompositeLink next = jac->head; 286ace3abfcSBarry Smith PetscBool iascii; 2874b9ad928SBarry Smith 2884b9ad928SBarry Smith PetscFunctionBegin; 289251f4c67SDmitry Karpeev ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 29032077d6dSBarry Smith if (iascii) { 2919dcbbd2bSBarry Smith ierr = PetscViewerASCIIPrintf(viewer,"Composite PC type - %s\n",PCCompositeTypes[jac->type]);CHKERRQ(ierr); 2924b9ad928SBarry Smith ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr); 2934b9ad928SBarry Smith ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 2944b9ad928SBarry Smith } 29532077d6dSBarry Smith if (iascii) { 2964b9ad928SBarry Smith ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 2974b9ad928SBarry Smith } 2984b9ad928SBarry Smith while (next) { 2994b9ad928SBarry Smith ierr = PCView(next->pc,viewer);CHKERRQ(ierr); 3004b9ad928SBarry Smith next = next->next; 3014b9ad928SBarry Smith } 30232077d6dSBarry Smith if (iascii) { 3034b9ad928SBarry Smith ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 3044b9ad928SBarry Smith ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 3054b9ad928SBarry Smith } 3064b9ad928SBarry Smith PetscFunctionReturn(0); 3074b9ad928SBarry Smith } 3084b9ad928SBarry Smith 3094b9ad928SBarry Smith /* ------------------------------------------------------------------------------*/ 3104b9ad928SBarry Smith 3114b9ad928SBarry Smith #undef __FUNCT__ 3124b9ad928SBarry Smith #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite" 3131e6b0712SBarry Smith static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha) 3144b9ad928SBarry Smith { 3154b9ad928SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 3165fd66863SKarl Rupp 3174b9ad928SBarry Smith PetscFunctionBegin; 3184b9ad928SBarry Smith jac->alpha = alpha; 3194b9ad928SBarry Smith PetscFunctionReturn(0); 3204b9ad928SBarry Smith } 3214b9ad928SBarry Smith 3224b9ad928SBarry Smith #undef __FUNCT__ 3234b9ad928SBarry Smith #define __FUNCT__ "PCCompositeSetType_Composite" 3241e6b0712SBarry Smith static PetscErrorCode PCCompositeSetType_Composite(PC pc,PCCompositeType type) 3254b9ad928SBarry Smith { 326fad69fbaSJed Brown PC_Composite *jac = (PC_Composite*)pc->data; 327fad69fbaSJed Brown 3284b9ad928SBarry Smith PetscFunctionBegin; 3294b9ad928SBarry Smith if (type == PC_COMPOSITE_ADDITIVE) { 3304b9ad928SBarry Smith pc->ops->apply = PCApply_Composite_Additive; 3312533e041SBarry Smith pc->ops->applytranspose = PCApplyTranspose_Composite_Additive; 332421e10b8SBarry Smith } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 3334b9ad928SBarry Smith pc->ops->apply = PCApply_Composite_Multiplicative; 3342533e041SBarry Smith pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative; 3354b9ad928SBarry Smith } else if (type == PC_COMPOSITE_SPECIAL) { 3364b9ad928SBarry Smith pc->ops->apply = PCApply_Composite_Special; 3370298fd71SBarry Smith pc->ops->applytranspose = NULL; 338ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Unkown composite preconditioner type"); 339fad69fbaSJed Brown jac->type = type; 3404b9ad928SBarry Smith PetscFunctionReturn(0); 3414b9ad928SBarry Smith } 3424b9ad928SBarry Smith 3434b9ad928SBarry Smith #undef __FUNCT__ 344c60c7ad4SBarry Smith #define __FUNCT__ "PCCompositeGetType_Composite" 345c60c7ad4SBarry Smith static PetscErrorCode PCCompositeGetType_Composite(PC pc,PCCompositeType *type) 346c60c7ad4SBarry Smith { 347c60c7ad4SBarry Smith PC_Composite *jac = (PC_Composite*)pc->data; 348c60c7ad4SBarry Smith 349c60c7ad4SBarry Smith PetscFunctionBegin; 350c60c7ad4SBarry Smith *type = jac->type; 351c60c7ad4SBarry Smith PetscFunctionReturn(0); 352c60c7ad4SBarry Smith } 353c60c7ad4SBarry Smith 354c60c7ad4SBarry Smith #undef __FUNCT__ 3554b9ad928SBarry Smith #define __FUNCT__ "PCCompositeAddPC_Composite" 3561e6b0712SBarry Smith static PetscErrorCode PCCompositeAddPC_Composite(PC pc,PCType type) 3574b9ad928SBarry Smith { 3584b9ad928SBarry Smith PC_Composite *jac; 3595a9f2f41SSatish Balay PC_CompositeLink next,ilink; 360dfbe8321SBarry Smith PetscErrorCode ierr; 36179416396SBarry Smith PetscInt cnt = 0; 3622dcb1b2aSMatthew Knepley const char *prefix; 3632dcb1b2aSMatthew Knepley char newprefix[8]; 3644b9ad928SBarry Smith 3654b9ad928SBarry Smith PetscFunctionBegin; 366b00a9115SJed Brown ierr = PetscNewLog(pc,&ilink);CHKERRQ(ierr); 3675a9f2f41SSatish Balay ilink->next = 0; 368ce94432eSBarry Smith ierr = PCCreate(PetscObjectComm((PetscObject)pc),&ilink->pc);CHKERRQ(ierr); 369ace3abfcSBarry Smith ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->pc);CHKERRQ(ierr); 3704b9ad928SBarry Smith 3714b9ad928SBarry Smith jac = (PC_Composite*)pc->data; 3724b9ad928SBarry Smith next = jac->head; 3734b9ad928SBarry Smith if (!next) { 3745a9f2f41SSatish Balay jac->head = ilink; 3750298fd71SBarry Smith ilink->previous = NULL; 3764b9ad928SBarry Smith } else { 3774b9ad928SBarry Smith cnt++; 3784b9ad928SBarry Smith while (next->next) { 3794b9ad928SBarry Smith next = next->next; 3804b9ad928SBarry Smith cnt++; 3814b9ad928SBarry Smith } 3825a9f2f41SSatish Balay next->next = ilink; 383421e10b8SBarry Smith ilink->previous = next; 3844b9ad928SBarry Smith } 3854b9ad928SBarry Smith ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 3865a9f2f41SSatish Balay ierr = PCSetOptionsPrefix(ilink->pc,prefix);CHKERRQ(ierr); 38713f74950SBarry Smith sprintf(newprefix,"sub_%d_",(int)cnt); 3885a9f2f41SSatish Balay ierr = PCAppendOptionsPrefix(ilink->pc,newprefix);CHKERRQ(ierr); 3894b9ad928SBarry Smith /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */ 3905a9f2f41SSatish Balay ierr = PCSetType(ilink->pc,type);CHKERRQ(ierr); 3914b9ad928SBarry Smith PetscFunctionReturn(0); 3924b9ad928SBarry Smith } 3934b9ad928SBarry Smith 3944b9ad928SBarry Smith #undef __FUNCT__ 3958e6eba06SBarry Smith #define __FUNCT__ "PCCompositeGetNumberPC_Composite" 3968e6eba06SBarry Smith static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc,PetscInt *n) 3978e6eba06SBarry Smith { 3988e6eba06SBarry Smith PC_Composite *jac; 3998e6eba06SBarry Smith PC_CompositeLink next; 4008e6eba06SBarry Smith 4018e6eba06SBarry Smith PetscFunctionBegin; 4028e6eba06SBarry Smith jac = (PC_Composite*)pc->data; 4038e6eba06SBarry Smith next = jac->head; 4048e6eba06SBarry Smith *n = 0; 4058e6eba06SBarry Smith while (next) { 4068e6eba06SBarry Smith next = next->next; 4078e6eba06SBarry Smith (*n) ++; 4088e6eba06SBarry Smith } 4098e6eba06SBarry Smith PetscFunctionReturn(0); 4108e6eba06SBarry Smith } 4118e6eba06SBarry Smith 4128e6eba06SBarry Smith #undef __FUNCT__ 4134b9ad928SBarry Smith #define __FUNCT__ "PCCompositeGetPC_Composite" 4141e6b0712SBarry Smith static PetscErrorCode PCCompositeGetPC_Composite(PC pc,PetscInt n,PC *subpc) 4154b9ad928SBarry Smith { 4164b9ad928SBarry Smith PC_Composite *jac; 4174b9ad928SBarry Smith PC_CompositeLink next; 41879416396SBarry Smith PetscInt i; 4194b9ad928SBarry Smith 4204b9ad928SBarry Smith PetscFunctionBegin; 4214b9ad928SBarry Smith jac = (PC_Composite*)pc->data; 4224b9ad928SBarry Smith next = jac->head; 4234b9ad928SBarry Smith for (i=0; i<n; i++) { 424ce94432eSBarry Smith if (!next->next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Not enough PCs in composite preconditioner"); 4254b9ad928SBarry Smith next = next->next; 4264b9ad928SBarry Smith } 4274b9ad928SBarry Smith *subpc = next->pc; 4284b9ad928SBarry Smith PetscFunctionReturn(0); 4294b9ad928SBarry Smith } 4304b9ad928SBarry Smith 4314b9ad928SBarry Smith /* -------------------------------------------------------------------------------- */ 4324b9ad928SBarry Smith #undef __FUNCT__ 4334b9ad928SBarry Smith #define __FUNCT__ "PCCompositeSetType" 434f39d8e23SSatish Balay /*@ 4354b9ad928SBarry Smith PCCompositeSetType - Sets the type of composite preconditioner. 4364b9ad928SBarry Smith 437ad4df100SBarry Smith Logically Collective on PC 4384b9ad928SBarry Smith 439c60c7ad4SBarry Smith Input Parameters: 4402a6744ebSBarry Smith + pc - the preconditioner context 4412a6744ebSBarry Smith - type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL 4424b9ad928SBarry Smith 4434b9ad928SBarry Smith Options Database Key: 4444b9ad928SBarry Smith . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type 4454b9ad928SBarry Smith 4464b9ad928SBarry Smith Level: Developer 4474b9ad928SBarry Smith 4484b9ad928SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative 4494b9ad928SBarry Smith @*/ 4507087cfbeSBarry Smith PetscErrorCode PCCompositeSetType(PC pc,PCCompositeType type) 4514b9ad928SBarry Smith { 4527bb14e67SBarry Smith PetscErrorCode ierr; 4534b9ad928SBarry Smith 4544b9ad928SBarry Smith PetscFunctionBegin; 4550700a824SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 456c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc,type,2); 4577bb14e67SBarry Smith ierr = PetscTryMethod(pc,"PCCompositeSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr); 4584b9ad928SBarry Smith PetscFunctionReturn(0); 4594b9ad928SBarry Smith } 4604b9ad928SBarry Smith 4614b9ad928SBarry Smith #undef __FUNCT__ 462c60c7ad4SBarry Smith #define __FUNCT__ "PCCompositeGetType" 463c60c7ad4SBarry Smith /*@ 464721f67b5SBarry Smith PCCompositeGetType - Gets the type of composite preconditioner. 465c60c7ad4SBarry Smith 466c60c7ad4SBarry Smith Logically Collective on PC 467c60c7ad4SBarry Smith 468c60c7ad4SBarry Smith Input Parameter: 469c60c7ad4SBarry Smith . pc - the preconditioner context 470c60c7ad4SBarry Smith 471c60c7ad4SBarry Smith Output Parameter: 472c60c7ad4SBarry Smith . type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL 473c60c7ad4SBarry Smith 474c60c7ad4SBarry Smith Options Database Key: 475c60c7ad4SBarry Smith . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type 476c60c7ad4SBarry Smith 477c60c7ad4SBarry Smith Level: Developer 478c60c7ad4SBarry Smith 479c60c7ad4SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative 480c60c7ad4SBarry Smith @*/ 481c60c7ad4SBarry Smith PetscErrorCode PCCompositeGetType(PC pc,PCCompositeType *type) 482c60c7ad4SBarry Smith { 483c60c7ad4SBarry Smith PetscErrorCode ierr; 484c60c7ad4SBarry Smith 485c60c7ad4SBarry Smith PetscFunctionBegin; 486c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 487c60c7ad4SBarry Smith ierr = PetscUseMethod(pc,"PCCompositeGetType_C",(PC,PCCompositeType*),(pc,type));CHKERRQ(ierr); 488c60c7ad4SBarry Smith PetscFunctionReturn(0); 489c60c7ad4SBarry Smith } 490c60c7ad4SBarry Smith 491c60c7ad4SBarry Smith #undef __FUNCT__ 4924b9ad928SBarry Smith #define __FUNCT__ "PCCompositeSpecialSetAlpha" 493f39d8e23SSatish Balay /*@ 4944b9ad928SBarry Smith PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner 4954b9ad928SBarry Smith for alphaI + R + S 4964b9ad928SBarry Smith 497ad4df100SBarry Smith Logically Collective on PC 4984b9ad928SBarry Smith 4994b9ad928SBarry Smith Input Parameter: 5004b9ad928SBarry Smith + pc - the preconditioner context 5014b9ad928SBarry Smith - alpha - scale on identity 5024b9ad928SBarry Smith 5034b9ad928SBarry Smith Level: Developer 5044b9ad928SBarry Smith 5054b9ad928SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative 5064b9ad928SBarry Smith @*/ 5077087cfbeSBarry Smith PetscErrorCode PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha) 5084b9ad928SBarry Smith { 5094ac538c5SBarry Smith PetscErrorCode ierr; 5104b9ad928SBarry Smith 5114b9ad928SBarry Smith PetscFunctionBegin; 5120700a824SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 513c5eb9154SBarry Smith PetscValidLogicalCollectiveScalar(pc,alpha,2); 5144ac538c5SBarry Smith ierr = PetscTryMethod(pc,"PCCompositeSpecialSetAlpha_C",(PC,PetscScalar),(pc,alpha));CHKERRQ(ierr); 5154b9ad928SBarry Smith PetscFunctionReturn(0); 5164b9ad928SBarry Smith } 5174b9ad928SBarry Smith 5184b9ad928SBarry Smith #undef __FUNCT__ 5194b9ad928SBarry Smith #define __FUNCT__ "PCCompositeAddPC" 5204b9ad928SBarry Smith /*@C 5214b9ad928SBarry Smith PCCompositeAddPC - Adds another PC to the composite PC. 5224b9ad928SBarry Smith 5234b9ad928SBarry Smith Collective on PC 5244b9ad928SBarry Smith 5254b9ad928SBarry Smith Input Parameters: 5262a6744ebSBarry Smith + pc - the preconditioner context 5272a6744ebSBarry Smith - type - the type of the new preconditioner 5284b9ad928SBarry Smith 5294b9ad928SBarry Smith Level: Developer 5304b9ad928SBarry Smith 5314b9ad928SBarry Smith .keywords: PC, composite preconditioner, add 5324b9ad928SBarry Smith @*/ 53319fd82e9SBarry Smith PetscErrorCode PCCompositeAddPC(PC pc,PCType type) 5344b9ad928SBarry Smith { 5354ac538c5SBarry Smith PetscErrorCode ierr; 5364b9ad928SBarry Smith 5374b9ad928SBarry Smith PetscFunctionBegin; 5380700a824SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 53919fd82e9SBarry Smith ierr = PetscTryMethod(pc,"PCCompositeAddPC_C",(PC,PCType),(pc,type));CHKERRQ(ierr); 5404b9ad928SBarry Smith PetscFunctionReturn(0); 5414b9ad928SBarry Smith } 5424b9ad928SBarry Smith 5434b9ad928SBarry Smith #undef __FUNCT__ 5448e6eba06SBarry Smith #define __FUNCT__ "PCCompositeGetNumberPC" 5458e6eba06SBarry Smith /*@ 5468e6eba06SBarry Smith PCCompositeGetNumberPC - Gets the number of PC objects in the composite PC. 5478e6eba06SBarry Smith 5488e6eba06SBarry Smith Not Collective 5498e6eba06SBarry Smith 5508e6eba06SBarry Smith Input Parameter: 5518e6eba06SBarry Smith . pc - the preconditioner context 5528e6eba06SBarry Smith 5538e6eba06SBarry Smith Output Parameter: 5548e6eba06SBarry Smith . num - the number of sub pcs 5558e6eba06SBarry Smith 5568e6eba06SBarry Smith Level: Developer 5578e6eba06SBarry Smith 5588e6eba06SBarry Smith .keywords: PC, get, composite preconditioner, sub preconditioner 5598e6eba06SBarry Smith 5608e6eba06SBarry Smith .seealso: PCCompositeGetPC() 5618e6eba06SBarry Smith @*/ 5628e6eba06SBarry Smith PetscErrorCode PCCompositeGetNumberPC(PC pc,PetscInt *num) 5638e6eba06SBarry Smith { 5648e6eba06SBarry Smith PetscErrorCode ierr; 5658e6eba06SBarry Smith 5668e6eba06SBarry Smith PetscFunctionBegin; 5678e6eba06SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 5688e6eba06SBarry Smith PetscValidIntPointer(num,2); 5698e6eba06SBarry Smith ierr = PetscUseMethod(pc,"PCCompositeGetNumberPC_C",(PC,PetscInt*),(pc,num));CHKERRQ(ierr); 5708e6eba06SBarry Smith PetscFunctionReturn(0); 5718e6eba06SBarry Smith } 5728e6eba06SBarry Smith 5738e6eba06SBarry Smith #undef __FUNCT__ 5744b9ad928SBarry Smith #define __FUNCT__ "PCCompositeGetPC" 575f39d8e23SSatish Balay /*@ 5764b9ad928SBarry Smith PCCompositeGetPC - Gets one of the PC objects in the composite PC. 5774b9ad928SBarry Smith 5784b9ad928SBarry Smith Not Collective 5794b9ad928SBarry Smith 5804b9ad928SBarry Smith Input Parameter: 5812a6744ebSBarry Smith + pc - the preconditioner context 5822a6744ebSBarry Smith - n - the number of the pc requested 5834b9ad928SBarry Smith 5844b9ad928SBarry Smith Output Parameters: 5854b9ad928SBarry Smith . subpc - the PC requested 5864b9ad928SBarry Smith 5874b9ad928SBarry Smith Level: Developer 5884b9ad928SBarry Smith 5894b9ad928SBarry Smith .keywords: PC, get, composite preconditioner, sub preconditioner 5904b9ad928SBarry Smith 5918e6eba06SBarry Smith .seealso: PCCompositeAddPC(), PCCompositeGetNumberPC() 5924b9ad928SBarry Smith @*/ 5937087cfbeSBarry Smith PetscErrorCode PCCompositeGetPC(PC pc,PetscInt n,PC *subpc) 5944b9ad928SBarry Smith { 5954ac538c5SBarry Smith PetscErrorCode ierr; 5964b9ad928SBarry Smith 5974b9ad928SBarry Smith PetscFunctionBegin; 5980700a824SBarry Smith PetscValidHeaderSpecific(pc,PC_CLASSID,1); 5994482741eSBarry Smith PetscValidPointer(subpc,3); 6004ac538c5SBarry Smith ierr = PetscUseMethod(pc,"PCCompositeGetPC_C",(PC,PetscInt,PC*),(pc,n,subpc));CHKERRQ(ierr); 6014b9ad928SBarry Smith PetscFunctionReturn(0); 6024b9ad928SBarry Smith } 6034b9ad928SBarry Smith 6044b9ad928SBarry Smith /* -------------------------------------------------------------------------------------------*/ 6054b9ad928SBarry Smith 6064b9ad928SBarry Smith /*MC 6074b9ad928SBarry Smith PCCOMPOSITE - Build a preconditioner by composing together several preconditioners 6084b9ad928SBarry Smith 6094b9ad928SBarry Smith Options Database Keys: 6102eab2d5bSJungho Lee + -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type 61149517cdeSBarry Smith . -pc_use_amat - Activates PCSetUseAmat() 61251f519a2SBarry Smith - -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose 6134b9ad928SBarry Smith 6144b9ad928SBarry Smith Level: intermediate 6154b9ad928SBarry Smith 6164b9ad928SBarry Smith Concepts: composing solvers 6174b9ad928SBarry Smith 6184b9ad928SBarry Smith Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more 6194b9ad928SBarry Smith inner PCs to be PCKSP. 6204b9ad928SBarry Smith Using a Krylov method inside another Krylov method can be dangerous (you get divergence or 621b3ef52cdSBarry Smith the incorrect answer) unless you use KSPFGMRES as the outer Krylov method 6224b9ad928SBarry Smith 6234b9ad928SBarry Smith 6244b9ad928SBarry Smith .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 6254b9ad928SBarry Smith PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(), 62649517cdeSBarry Smith PCCompositeGetPC(), PCSetUseAmat() 6274b9ad928SBarry Smith 6284b9ad928SBarry Smith M*/ 6294b9ad928SBarry Smith 6304b9ad928SBarry Smith #undef __FUNCT__ 6314b9ad928SBarry Smith #define __FUNCT__ "PCCreate_Composite" 6328cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc) 6334b9ad928SBarry Smith { 634dfbe8321SBarry Smith PetscErrorCode ierr; 6354b9ad928SBarry Smith PC_Composite *jac; 6364b9ad928SBarry Smith 6374b9ad928SBarry Smith PetscFunctionBegin; 638b00a9115SJed Brown ierr = PetscNewLog(pc,&jac);CHKERRQ(ierr); 6392fa5cd67SKarl Rupp 6404b9ad928SBarry Smith pc->ops->apply = PCApply_Composite_Additive; 6412533e041SBarry Smith pc->ops->applytranspose = PCApplyTranspose_Composite_Additive; 6424b9ad928SBarry Smith pc->ops->setup = PCSetUp_Composite; 64369d2c0f9SBarry Smith pc->ops->reset = PCReset_Composite; 6444b9ad928SBarry Smith pc->ops->destroy = PCDestroy_Composite; 6454b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_Composite; 6464b9ad928SBarry Smith pc->ops->view = PCView_Composite; 6474b9ad928SBarry Smith pc->ops->applyrichardson = 0; 6484b9ad928SBarry Smith 6494b9ad928SBarry Smith pc->data = (void*)jac; 6504b9ad928SBarry Smith jac->type = PC_COMPOSITE_ADDITIVE; 6514b9ad928SBarry Smith jac->work1 = 0; 6524b9ad928SBarry Smith jac->work2 = 0; 6534b9ad928SBarry Smith jac->head = 0; 6544b9ad928SBarry Smith 655bdf89e91SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeSetType_C",PCCompositeSetType_Composite);CHKERRQ(ierr); 656c60c7ad4SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetType_C",PCCompositeGetType_Composite);CHKERRQ(ierr); 657bdf89e91SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeAddPC_C",PCCompositeAddPC_Composite);CHKERRQ(ierr); 6588e6eba06SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetNumberPC_C",PCCompositeGetNumberPC_Composite);CHKERRQ(ierr); 659bdf89e91SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetPC_C",PCCompositeGetPC_Composite);CHKERRQ(ierr); 660bdf89e91SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)pc,"PCCompositeSpecialSetAlpha_C",PCCompositeSpecialSetAlpha_Composite);CHKERRQ(ierr); 6614b9ad928SBarry Smith PetscFunctionReturn(0); 6624b9ad928SBarry Smith } 6634b9ad928SBarry Smith 664