1daa6d063SJed Brown 2c6db04a5SJed Brown #include <private/pcimpl.h> /*I "petscpc.h" I*/ 3daa6d063SJed Brown 4daa6d063SJed Brown typedef struct { 5ace3abfcSBarry Smith PetscBool allocated; 6ace3abfcSBarry Smith PetscBool scalediag; 7daa6d063SJed Brown KSP kspL; 8daa6d063SJed Brown Vec scale; 9daa6d063SJed Brown Vec x0,y0,x1; 107e8cb189SBarry Smith Mat L; /* keep a copy to reuse when obtained with L = A10*A01 */ 11daa6d063SJed Brown } PC_LSC; 12daa6d063SJed Brown 13daa6d063SJed Brown #undef __FUNCT__ 14daa6d063SJed Brown #define __FUNCT__ "PCLSCAllocate_Private" 15daa6d063SJed Brown static PetscErrorCode PCLSCAllocate_Private(PC pc) 16daa6d063SJed Brown { 17daa6d063SJed Brown PC_LSC *lsc = (PC_LSC*)pc->data; 18daa6d063SJed Brown Mat A; 19daa6d063SJed Brown PetscErrorCode ierr; 20daa6d063SJed Brown 21daa6d063SJed Brown PetscFunctionBegin; 22daa6d063SJed Brown if (lsc->allocated) PetscFunctionReturn(0); 23daa6d063SJed Brown ierr = KSPCreate(((PetscObject)pc)->comm,&lsc->kspL);CHKERRQ(ierr); 247e8cb189SBarry Smith ierr = PetscObjectIncrementTabLevel((PetscObject)lsc->kspL,(PetscObject)pc,1);CHKERRQ(ierr); 25daa6d063SJed Brown ierr = KSPSetType(lsc->kspL,KSPPREONLY);CHKERRQ(ierr); 26daa6d063SJed Brown ierr = KSPSetOptionsPrefix(lsc->kspL,((PetscObject)pc)->prefix);CHKERRQ(ierr); 27daa6d063SJed Brown ierr = KSPAppendOptionsPrefix(lsc->kspL,"lsc_");CHKERRQ(ierr); 28daa6d063SJed Brown ierr = KSPSetFromOptions(lsc->kspL);CHKERRQ(ierr); 29daa6d063SJed Brown ierr = MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 30daa6d063SJed Brown ierr = MatGetVecs(A,&lsc->x0,&lsc->y0);CHKERRQ(ierr); 31daa6d063SJed Brown ierr = MatGetVecs(pc->pmat,&lsc->x1,PETSC_NULL);CHKERRQ(ierr); 32daa6d063SJed Brown if (lsc->scalediag) { 33daa6d063SJed Brown ierr = VecDuplicate(lsc->x0,&lsc->scale);CHKERRQ(ierr); 34daa6d063SJed Brown } 35daa6d063SJed Brown lsc->allocated = PETSC_TRUE; 36daa6d063SJed Brown PetscFunctionReturn(0); 37daa6d063SJed Brown } 38daa6d063SJed Brown 39daa6d063SJed Brown #undef __FUNCT__ 40daa6d063SJed Brown #define __FUNCT__ "PCSetUp_LSC" 41daa6d063SJed Brown static PetscErrorCode PCSetUp_LSC(PC pc) 42daa6d063SJed Brown { 43daa6d063SJed Brown PC_LSC *lsc = (PC_LSC*)pc->data; 447e8cb189SBarry Smith Mat L,Lp,B,C; 45daa6d063SJed Brown PetscErrorCode ierr; 46daa6d063SJed Brown 47daa6d063SJed Brown PetscFunctionBegin; 48daa6d063SJed Brown ierr = PCLSCAllocate_Private(pc);CHKERRQ(ierr); 49daa6d063SJed Brown ierr = PetscObjectQuery((PetscObject)pc->pmat,"LSC_L",(PetscObject*)&L);CHKERRQ(ierr); 50daa6d063SJed Brown ierr = PetscObjectQuery((PetscObject)pc->pmat,"LSC_Lp",(PetscObject*)&Lp);CHKERRQ(ierr); 517e8cb189SBarry Smith if (!L) { 527e8cb189SBarry Smith ierr = MatSchurComplementGetSubmatrices(pc->mat,PETSC_NULL,PETSC_NULL,&B,&C,PETSC_NULL);CHKERRQ(ierr); 537e8cb189SBarry Smith if (!lsc->L) { 547e8cb189SBarry Smith ierr = MatMatMult(C,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lsc->L);CHKERRQ(ierr); 557e8cb189SBarry Smith } else { 567e8cb189SBarry Smith ierr = MatMatMult(C,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&lsc->L);CHKERRQ(ierr); 577e8cb189SBarry Smith } 587e8cb189SBarry Smith Lp = L = lsc->L; 597e8cb189SBarry Smith } 60daa6d063SJed Brown if (lsc->scale) { 61daa6d063SJed Brown Mat Ap; 62daa6d063SJed Brown ierr = MatSchurComplementGetSubmatrices(pc->mat,PETSC_NULL,&Ap,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 63daa6d063SJed Brown ierr = MatGetDiagonal(Ap,lsc->scale);CHKERRQ(ierr); /* Should be the mass matrix, but we don't have plumbing for that yet */ 64daa6d063SJed Brown ierr = VecReciprocal(lsc->scale);CHKERRQ(ierr); 65daa6d063SJed Brown } 66daa6d063SJed Brown ierr = KSPSetOperators(lsc->kspL,L,Lp,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 67daa6d063SJed Brown PetscFunctionReturn(0); 68daa6d063SJed Brown } 69daa6d063SJed Brown 70daa6d063SJed Brown #undef __FUNCT__ 71daa6d063SJed Brown #define __FUNCT__ "PCApply_LSC" 72daa6d063SJed Brown static PetscErrorCode PCApply_LSC(PC pc,Vec x,Vec y) 73daa6d063SJed Brown { 74daa6d063SJed Brown PC_LSC *lsc = (PC_LSC*)pc->data; 75daa6d063SJed Brown Mat A,B,C; 76daa6d063SJed Brown PetscErrorCode ierr; 77daa6d063SJed Brown 78daa6d063SJed Brown PetscFunctionBegin; 79daa6d063SJed Brown ierr = MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,&B,&C,PETSC_NULL);CHKERRQ(ierr); 80daa6d063SJed Brown ierr = KSPSolve(lsc->kspL,x,lsc->x1);CHKERRQ(ierr); 81daa6d063SJed Brown ierr = MatMult(B,lsc->x1,lsc->x0);CHKERRQ(ierr); 82daa6d063SJed Brown if (lsc->scale) { 83daa6d063SJed Brown ierr = VecPointwiseMult(lsc->x0,lsc->x0,lsc->scale);CHKERRQ(ierr); 84daa6d063SJed Brown } 85daa6d063SJed Brown ierr = MatMult(A,lsc->x0,lsc->y0);CHKERRQ(ierr); 86daa6d063SJed Brown if (lsc->scale) { 87daa6d063SJed Brown ierr = VecPointwiseMult(lsc->y0,lsc->y0,lsc->scale);CHKERRQ(ierr); 88daa6d063SJed Brown } 89daa6d063SJed Brown ierr = MatMult(C,lsc->y0,lsc->x1);CHKERRQ(ierr); 90daa6d063SJed Brown ierr = KSPSolve(lsc->kspL,lsc->x1,y);CHKERRQ(ierr); 91daa6d063SJed Brown PetscFunctionReturn(0); 92daa6d063SJed Brown } 93daa6d063SJed Brown 94daa6d063SJed Brown #undef __FUNCT__ 95*a06653b4SBarry Smith #define __FUNCT__ "PCReset_LSC" 96*a06653b4SBarry Smith static PetscErrorCode PCReset_LSC(PC pc) 97daa6d063SJed Brown { 98daa6d063SJed Brown PC_LSC *lsc = (PC_LSC*)pc->data; 99daa6d063SJed Brown PetscErrorCode ierr; 100daa6d063SJed Brown 101daa6d063SJed Brown PetscFunctionBegin; 102daa6d063SJed Brown if (lsc->x0) {ierr = VecDestroy(lsc->x0);CHKERRQ(ierr);} 103daa6d063SJed Brown if (lsc->y0) {ierr = VecDestroy(lsc->y0);CHKERRQ(ierr);} 104daa6d063SJed Brown if (lsc->x1) {ierr = VecDestroy(lsc->x1);CHKERRQ(ierr);} 105daa6d063SJed Brown if (lsc->scale) {ierr = VecDestroy(lsc->scale);CHKERRQ(ierr);} 106daa6d063SJed Brown if (lsc->kspL) {ierr = KSPDestroy(lsc->kspL);CHKERRQ(ierr);} 1077e8cb189SBarry Smith if (lsc->L) {ierr = MatDestroy(lsc->L);CHKERRQ(ierr);} 108*a06653b4SBarry Smith PetscFunctionReturn(0); 109*a06653b4SBarry Smith } 110*a06653b4SBarry Smith 111*a06653b4SBarry Smith #undef __FUNCT__ 112*a06653b4SBarry Smith #define __FUNCT__ "PCDestroy_LSC" 113*a06653b4SBarry Smith static PetscErrorCode PCDestroy_LSC(PC pc) 114*a06653b4SBarry Smith { 115*a06653b4SBarry Smith PC_LSC *lsc = (PC_LSC*)pc->data; 116*a06653b4SBarry Smith PetscErrorCode ierr; 117*a06653b4SBarry Smith 118*a06653b4SBarry Smith PetscFunctionBegin; 119*a06653b4SBarry Smith ierr = PCReset_LSC(pc);CHKERRQ(ierr); 120c31cb41cSBarry Smith ierr = PetscFree(pc->data);CHKERRQ(ierr); 121daa6d063SJed Brown PetscFunctionReturn(0); 122daa6d063SJed Brown } 123daa6d063SJed Brown 124daa6d063SJed Brown #undef __FUNCT__ 125daa6d063SJed Brown #define __FUNCT__ "PCSetFromOptions_LSC" 126daa6d063SJed Brown static PetscErrorCode PCSetFromOptions_LSC(PC pc) 127daa6d063SJed Brown { 128daa6d063SJed Brown PC_LSC *lsc = (PC_LSC*)pc->data; 129daa6d063SJed Brown PetscErrorCode ierr; 130daa6d063SJed Brown 131daa6d063SJed Brown PetscFunctionBegin; 132daa6d063SJed Brown ierr = PetscOptionsHead("LSC options");CHKERRQ(ierr); 133daa6d063SJed Brown { 134acfcf0e5SJed Brown ierr = PetscOptionsBool("-pc_lsc_scale_diag","Use diagonal of velocity block (A) for scaling","None",lsc->scalediag,&lsc->scalediag,PETSC_NULL);CHKERRQ(ierr); 135daa6d063SJed Brown } 136daa6d063SJed Brown ierr = PetscOptionsTail();CHKERRQ(ierr); 137daa6d063SJed Brown PetscFunctionReturn(0); 138daa6d063SJed Brown } 139daa6d063SJed Brown 1407e8cb189SBarry Smith #undef __FUNCT__ 1417e8cb189SBarry Smith #define __FUNCT__ "PCView_LSC" 1427e8cb189SBarry Smith static PetscErrorCode PCView_LSC(PC pc,PetscViewer viewer) 1437e8cb189SBarry Smith { 1447e8cb189SBarry Smith PC_LSC *jac = (PC_LSC*)pc->data; 1457e8cb189SBarry Smith PetscErrorCode ierr; 1467e8cb189SBarry Smith PetscBool iascii; 1477e8cb189SBarry Smith 1487e8cb189SBarry Smith PetscFunctionBegin; 1497e8cb189SBarry Smith ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 1507e8cb189SBarry Smith if (iascii) { 1517e8cb189SBarry Smith ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1527e8cb189SBarry Smith ierr = KSPView(jac->kspL,viewer);CHKERRQ(ierr); 1537e8cb189SBarry Smith ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1547e8cb189SBarry Smith } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for LSC",((PetscObject)viewer)->type_name); 1557e8cb189SBarry Smith PetscFunctionReturn(0); 1567e8cb189SBarry Smith } 1577e8cb189SBarry Smith 158daa6d063SJed Brown /*MC 159daa6d063SJed Brown PCLSC - Preconditioning for Schur complements, based on Least Squares Commutators 160daa6d063SJed Brown 161daa6d063SJed Brown Options Database Key: 162daa6d063SJed Brown . -pc_lsc_scale_diag - Use the diagonal of A for scaling 163daa6d063SJed Brown 164daa6d063SJed Brown Level: intermediate 165daa6d063SJed Brown 166daa6d063SJed Brown Notes: 167daa6d063SJed Brown This preconditioner will normally be used with PCFieldSplit to precondition the Schur complement, but 168daa6d063SJed Brown it can be used for any Schur complement system. Consider the Schur complement 169daa6d063SJed Brown 170daa6d063SJed Brown .vb 1717e8cb189SBarry Smith S = A11 - A10 inv(A00) A01 172daa6d063SJed Brown .ve 173daa6d063SJed Brown 1747e8cb189SBarry Smith PCLSC currently doesn't do anything with A11, so let's assume it is 0. The idea is that a good approximation to 175daa6d063SJed Brown inv(S) is given by 176daa6d063SJed Brown 177daa6d063SJed Brown .vb 1787e8cb189SBarry Smith inv(A10 A01) A10 A00 A01 inv(A10 A01) 179daa6d063SJed Brown .ve 180daa6d063SJed Brown 1817e8cb189SBarry Smith The product A10 A01 can be computed for you, but you can provide it (this is 1827e8cb189SBarry Smith usually more efficient anyway). In the case of incompressible flow, A10 A10 is a Laplacian, call it L. The current 183daa6d063SJed Brown interface is to hang L and a preconditioning matrix Lp on the preconditioning matrix. 184daa6d063SJed Brown 185daa6d063SJed Brown If you had called KSPSetOperators(ksp,S,Sp,flg), S should have type MATSCHURCOMPLEMENT and Sp can be any type you 186daa6d063SJed Brown like (PCLSC doesn't use it directly) but should have matrices composed with it, under the names "LSC_L" and "LSC_Lp". 187daa6d063SJed Brown For example, you might have setup code like this 188daa6d063SJed Brown 189daa6d063SJed Brown .vb 190daa6d063SJed Brown PetscObjectCompose((PetscObject)Sp,"LSC_L",(PetscObject)L); 191daa6d063SJed Brown PetscObjectCompose((PetscObject)Sp,"LSC_Lp",(PetscObject)Lp); 192daa6d063SJed Brown .ve 193daa6d063SJed Brown 194daa6d063SJed Brown And then your Jacobian assembly would look like 195daa6d063SJed Brown 196daa6d063SJed Brown .vb 197daa6d063SJed Brown PetscObjectQuery((PetscObject)Sp,"LSC_L",(PetscObject*)&L); 198daa6d063SJed Brown PetscObjectQuery((PetscObject)Sp,"LSC_Lp",(PetscObject*)&Lp); 199daa6d063SJed Brown if (L) { assembly L } 200daa6d063SJed Brown if (Lp) { assemble Lp } 201daa6d063SJed Brown .ve 202daa6d063SJed Brown 203daa6d063SJed Brown With this, you should be able to choose LSC preconditioning, using e.g. ML's algebraic multigrid to solve with L 204daa6d063SJed Brown 205daa6d063SJed Brown .vb 206daa6d063SJed Brown -fieldsplit_1_pc_type lsc -fieldsplit_1_lsc_pc_type ml 207daa6d063SJed Brown .ve 208daa6d063SJed Brown 209daa6d063SJed Brown Since we do not use the values in Sp, you can still put an assembled matrix there to use normal preconditioners. 210daa6d063SJed Brown 211daa6d063SJed Brown Concepts: physics based preconditioners, block preconditioners 212daa6d063SJed Brown 213daa6d063SJed Brown .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCFIELDSPLIT, 214daa6d063SJed Brown PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition(), 215daa6d063SJed Brown MatCreateSchurComplement() 216daa6d063SJed Brown M*/ 217daa6d063SJed Brown 218daa6d063SJed Brown EXTERN_C_BEGIN 219daa6d063SJed Brown #undef __FUNCT__ 220daa6d063SJed Brown #define __FUNCT__ "PCCreate_LSC" 2217087cfbeSBarry Smith PetscErrorCode PCCreate_LSC(PC pc) 222daa6d063SJed Brown { 223daa6d063SJed Brown PC_LSC *lsc; 224daa6d063SJed Brown PetscErrorCode ierr; 225daa6d063SJed Brown 226daa6d063SJed Brown PetscFunctionBegin; 227daa6d063SJed Brown ierr = PetscNewLog(pc,PC_LSC,&lsc);CHKERRQ(ierr); 228daa6d063SJed Brown pc->data = (void*)lsc; 229daa6d063SJed Brown 230daa6d063SJed Brown pc->ops->apply = PCApply_LSC; 231daa6d063SJed Brown pc->ops->applytranspose = 0; 232daa6d063SJed Brown pc->ops->setup = PCSetUp_LSC; 233*a06653b4SBarry Smith pc->ops->reset = PCReset_LSC; 234daa6d063SJed Brown pc->ops->destroy = PCDestroy_LSC; 235daa6d063SJed Brown pc->ops->setfromoptions = PCSetFromOptions_LSC; 2367e8cb189SBarry Smith pc->ops->view = PCView_LSC; 237daa6d063SJed Brown pc->ops->applyrichardson = 0; 238daa6d063SJed Brown PetscFunctionReturn(0); 239daa6d063SJed Brown } 240daa6d063SJed Brown EXTERN_C_END 241