1dba47a55SKris Buschelman 24b9ad928SBarry Smith /* 34b9ad928SBarry Smith Defines the multigrid preconditioner interface. 44b9ad928SBarry Smith */ 5af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 641b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h> 71e25c274SJed Brown #include <petscdm.h> 8391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *); 94b9ad928SBarry Smith 10f3b08a26SMatthew G. Knepley /* 11f3b08a26SMatthew G. Knepley Contains the list of registered coarse space construction routines 12f3b08a26SMatthew G. Knepley */ 13f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL; 14f3b08a26SMatthew G. Knepley 159371c9d4SSatish Balay PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) { 1631567311SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1731567311SBarry Smith PC_MG_Levels *mgc, *mglevels = *mglevelsin; 1831567311SBarry Smith PetscInt cycles = (mglevels->level == 1) ? 1 : (PetscInt)mglevels->cycles; 194b9ad928SBarry Smith 204b9ad928SBarry Smith PetscFunctionBegin; 219566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 22fcb023d4SJed Brown if (!transpose) { 2330b0564aSStefano Zampini if (matapp) { 249566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */ 259566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL)); 2630b0564aSStefano Zampini } else { 279566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */ 289566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 2930b0564aSStefano Zampini } 30fcb023d4SJed Brown } else { 3128b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 329566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */ 339566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 34fcb023d4SJed Brown } 359566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 3631567311SBarry Smith if (mglevels->level) { /* not the coarsest grid */ 379566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0)); 38*48a46eb9SPierre Jolivet if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R)); 39fcb023d4SJed Brown if (!transpose) { 409566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 419566063dSJacob Faibussowitsch else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 42fcb023d4SJed Brown } else { 439566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 449566063dSJacob Faibussowitsch else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 45fcb023d4SJed Brown } 469566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0)); 474b9ad928SBarry Smith 484b9ad928SBarry Smith /* if on finest level and have convergence criteria set */ 4931567311SBarry Smith if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) { 504b9ad928SBarry Smith PetscReal rnorm; 519566063dSJacob Faibussowitsch PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm)); 524b9ad928SBarry Smith if (rnorm <= mg->ttol) { 5370441072SBarry Smith if (rnorm < mg->abstol) { 544d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_ATOL; 559566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol)); 564b9ad928SBarry Smith } else { 574d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_RTOL; 589566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n", (double)rnorm, (double)mg->ttol)); 594b9ad928SBarry Smith } 604b9ad928SBarry Smith PetscFunctionReturn(0); 614b9ad928SBarry Smith } 624b9ad928SBarry Smith } 634b9ad928SBarry Smith 6431567311SBarry Smith mgc = *(mglevelsin - 1); 659566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 66fcb023d4SJed Brown if (!transpose) { 679566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B)); 689566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b)); 69fcb023d4SJed Brown } else { 709566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B)); 719566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b)); 72fcb023d4SJed Brown } 739566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 7430b0564aSStefano Zampini if (matapp) { 7530b0564aSStefano Zampini if (!mgc->X) { 769566063dSJacob Faibussowitsch PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X)); 7730b0564aSStefano Zampini } else { 789566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mgc->X)); 7930b0564aSStefano Zampini } 8030b0564aSStefano Zampini } else { 819566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mgc->x)); 8230b0564aSStefano Zampini } 83*48a46eb9SPierre Jolivet while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason)); 849566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 85fcb023d4SJed Brown if (!transpose) { 869566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X)); 879566063dSJacob Faibussowitsch else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x)); 88fcb023d4SJed Brown } else { 899566063dSJacob Faibussowitsch PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x)); 90fcb023d4SJed Brown } 919566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 929566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 93fcb023d4SJed Brown if (!transpose) { 9430b0564aSStefano Zampini if (matapp) { 959566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */ 969566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL)); 9730b0564aSStefano Zampini } else { 989566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */ 999566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 10030b0564aSStefano Zampini } 101fcb023d4SJed Brown } else { 10228b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 1039566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */ 1049566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 105fcb023d4SJed Brown } 10641b6fd38SMatthew G. Knepley if (mglevels->cr) { 10728b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 10841b6fd38SMatthew G. Knepley /* TODO Turn on copy and turn off noisy if we have an exact solution 1099566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->x, mglevels->crx)); 1109566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->b, mglevels->crb)); */ 1119566063dSJacob Faibussowitsch PetscCall(KSPSetNoisy_Private(mglevels->crx)); 1129566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */ 1139566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx)); 11441b6fd38SMatthew G. Knepley } 1159566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 1164b9ad928SBarry Smith } 1174b9ad928SBarry Smith PetscFunctionReturn(0); 1184b9ad928SBarry Smith } 1194b9ad928SBarry Smith 1209371c9d4SSatish Balay static PetscErrorCode PCApplyRichardson_MG(PC pc, Vec b, Vec x, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt its, PetscBool zeroguess, PetscInt *outits, PCRichardsonConvergedReason *reason) { 121f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 122f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 123391689abSStefano Zampini PC tpc; 124391689abSStefano Zampini PetscBool changeu, changed; 125f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 1264b9ad928SBarry Smith 1274b9ad928SBarry Smith PetscFunctionBegin; 128a762d673SBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 129a762d673SBarry Smith for (i = 0; i < levels; i++) { 130a762d673SBarry Smith if (!mglevels[i]->A) { 1319566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 1329566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 133a762d673SBarry Smith } 134a762d673SBarry Smith } 135391689abSStefano Zampini 1369566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 1379566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 1389566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 1399566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 140391689abSStefano Zampini if (!changed && !changeu) { 1419566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 142f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 143391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 144391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 145391689abSStefano Zampini Vec *vec; 146391689abSStefano Zampini 1479566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 148391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 1499566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 150391689abSStefano Zampini } 1519566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 152391689abSStefano Zampini } 153f3fbd535SBarry Smith mglevels[levels - 1]->x = x; 1544b9ad928SBarry Smith 15531567311SBarry Smith mg->rtol = rtol; 15631567311SBarry Smith mg->abstol = abstol; 15731567311SBarry Smith mg->dtol = dtol; 1584b9ad928SBarry Smith if (rtol) { 1594b9ad928SBarry Smith /* compute initial residual norm for relative convergence test */ 1604b9ad928SBarry Smith PetscReal rnorm; 1617319c654SBarry Smith if (zeroguess) { 1629566063dSJacob Faibussowitsch PetscCall(VecNorm(b, NORM_2, &rnorm)); 1637319c654SBarry Smith } else { 1649566063dSJacob Faibussowitsch PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w)); 1659566063dSJacob Faibussowitsch PetscCall(VecNorm(w, NORM_2, &rnorm)); 1667319c654SBarry Smith } 16731567311SBarry Smith mg->ttol = PetscMax(rtol * rnorm, abstol); 1682fa5cd67SKarl Rupp } else if (abstol) mg->ttol = abstol; 1692fa5cd67SKarl Rupp else mg->ttol = 0.0; 1704b9ad928SBarry Smith 1714d0a8057SBarry Smith /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 172336babb1SJed Brown stop prematurely due to small residual */ 1734d0a8057SBarry Smith for (i = 1; i < levels; i++) { 1749566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); 175f3fbd535SBarry Smith if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 17623067569SBarry Smith /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */ 1779566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1789566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); 1794b9ad928SBarry Smith } 1804d0a8057SBarry Smith } 1814d0a8057SBarry Smith 1824d0a8057SBarry Smith *reason = (PCRichardsonConvergedReason)0; 1834d0a8057SBarry Smith for (i = 0; i < its; i++) { 1849566063dSJacob Faibussowitsch PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason)); 1854d0a8057SBarry Smith if (*reason) break; 1864d0a8057SBarry Smith } 1874d0a8057SBarry Smith if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 1884d0a8057SBarry Smith *outits = i; 189391689abSStefano Zampini if (!changed && !changeu) mglevels[levels - 1]->b = NULL; 1904b9ad928SBarry Smith PetscFunctionReturn(0); 1914b9ad928SBarry Smith } 1924b9ad928SBarry Smith 1939371c9d4SSatish Balay PetscErrorCode PCReset_MG(PC pc) { 1943aeaf226SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1953aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 1962b3cbbdaSStefano Zampini PetscInt i, n; 1973aeaf226SBarry Smith 1983aeaf226SBarry Smith PetscFunctionBegin; 1993aeaf226SBarry Smith if (mglevels) { 2003aeaf226SBarry Smith n = mglevels[0]->levels; 2013aeaf226SBarry Smith for (i = 0; i < n - 1; i++) { 2029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->r)); 2039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->b)); 2049566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->x)); 2059566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->R)); 2069566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 2079566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 2089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crx)); 2099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crb)); 2109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->restrct)); 2119566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->interpolate)); 2129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->inject)); 2139566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->rscale)); 2143aeaf226SBarry Smith } 2159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crx)); 2169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crb)); 217391689abSStefano Zampini /* this is not null only if the smoother on the finest level 218391689abSStefano Zampini changes the rhs during PreSolve */ 2199566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->b)); 2209566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[n - 1]->B)); 2213aeaf226SBarry Smith 2223aeaf226SBarry Smith for (i = 0; i < n; i++) { 2232b3cbbdaSStefano Zampini PetscCall(MatDestroy(&mglevels[i]->coarseSpace)); 2249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->A)); 225*48a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd)); 2269566063dSJacob Faibussowitsch PetscCall(KSPReset(mglevels[i]->smoothu)); 2279566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr)); 2283aeaf226SBarry Smith } 229f3b08a26SMatthew G. Knepley mg->Nc = 0; 2303aeaf226SBarry Smith } 2313aeaf226SBarry Smith PetscFunctionReturn(0); 2323aeaf226SBarry Smith } 2333aeaf226SBarry Smith 23441b6fd38SMatthew G. Knepley /* Implementing CR 23541b6fd38SMatthew G. Knepley 23641b6fd38SMatthew G. Knepley We only want to make corrections that ``do not change'' the coarse solution. What we mean by not changing is that if I prolong my coarse solution to the fine grid and then inject that fine solution back to the coarse grid, I get the same answer. Injection is what Brannick calls R. We want the complementary projector to Inj, which we will call S, after Brannick, so that Inj S = 0. Now the orthogonal projector onto the range of Inj^T is 23741b6fd38SMatthew G. Knepley 23841b6fd38SMatthew G. Knepley Inj^T (Inj Inj^T)^{-1} Inj 23941b6fd38SMatthew G. Knepley 24041b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have 24141b6fd38SMatthew G. Knepley 24241b6fd38SMatthew G. Knepley Inj^T Inj 24341b6fd38SMatthew G. Knepley 24441b6fd38SMatthew G. Knepley and 24541b6fd38SMatthew G. Knepley 24641b6fd38SMatthew G. Knepley S = I - Inj^T Inj 24741b6fd38SMatthew G. Knepley 24841b6fd38SMatthew G. Knepley since 24941b6fd38SMatthew G. Knepley 25041b6fd38SMatthew G. Knepley Inj S = Inj - (Inj Inj^T) Inj = 0. 25141b6fd38SMatthew G. Knepley 25241b6fd38SMatthew G. Knepley Brannick suggests 25341b6fd38SMatthew G. Knepley 25441b6fd38SMatthew G. Knepley A \to S^T A S \qquad\mathrm{and}\qquad M \to S^T M S 25541b6fd38SMatthew G. Knepley 25641b6fd38SMatthew G. Knepley but I do not think his :math:`S^T S = I` is correct. Our S is an orthogonal projector, so :math:`S^T S = S^2 = S`. We will use 25741b6fd38SMatthew G. Knepley 25841b6fd38SMatthew G. Knepley M^{-1} A \to S M^{-1} A S 25941b6fd38SMatthew G. Knepley 26041b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left. 26141b6fd38SMatthew G. Knepley 26241b6fd38SMatthew G. Knepley Check: || Inj P - I ||_F < tol 26341b6fd38SMatthew G. Knepley Check: In general, Inj Inj^T = I 26441b6fd38SMatthew G. Knepley */ 26541b6fd38SMatthew G. Knepley 26641b6fd38SMatthew G. Knepley typedef struct { 26741b6fd38SMatthew G. Knepley PC mg; /* The PCMG object */ 26841b6fd38SMatthew G. Knepley PetscInt l; /* The multigrid level for this solver */ 26941b6fd38SMatthew G. Knepley Mat Inj; /* The injection matrix */ 27041b6fd38SMatthew G. Knepley Mat S; /* I - Inj^T Inj */ 27141b6fd38SMatthew G. Knepley } CRContext; 27241b6fd38SMatthew G. Knepley 2739371c9d4SSatish Balay static PetscErrorCode CRSetup_Private(PC pc) { 27441b6fd38SMatthew G. Knepley CRContext *ctx; 27541b6fd38SMatthew G. Knepley Mat It; 27641b6fd38SMatthew G. Knepley 27741b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2789566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 2799566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It)); 28028b400f6SJacob Faibussowitsch PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG"); 2819566063dSJacob Faibussowitsch PetscCall(MatCreateTranspose(It, &ctx->Inj)); 2829566063dSJacob Faibussowitsch PetscCall(MatCreateNormal(ctx->Inj, &ctx->S)); 2839566063dSJacob Faibussowitsch PetscCall(MatScale(ctx->S, -1.0)); 2849566063dSJacob Faibussowitsch PetscCall(MatShift(ctx->S, 1.0)); 28541b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 28641b6fd38SMatthew G. Knepley } 28741b6fd38SMatthew G. Knepley 2889371c9d4SSatish Balay static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y) { 28941b6fd38SMatthew G. Knepley CRContext *ctx; 29041b6fd38SMatthew G. Knepley 29141b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2929566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 2939566063dSJacob Faibussowitsch PetscCall(MatMult(ctx->S, x, y)); 29441b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 29541b6fd38SMatthew G. Knepley } 29641b6fd38SMatthew G. Knepley 2979371c9d4SSatish Balay static PetscErrorCode CRDestroy_Private(PC pc) { 29841b6fd38SMatthew G. Knepley CRContext *ctx; 29941b6fd38SMatthew G. Knepley 30041b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3019566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 3029566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->Inj)); 3039566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->S)); 3049566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 3059566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(pc, NULL)); 30641b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 30741b6fd38SMatthew G. Knepley } 30841b6fd38SMatthew G. Knepley 3099371c9d4SSatish Balay static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr) { 31041b6fd38SMatthew G. Knepley CRContext *ctx; 31141b6fd38SMatthew G. Knepley 31241b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3139566063dSJacob Faibussowitsch PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr)); 3149566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)")); 3159566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(1, &ctx)); 31641b6fd38SMatthew G. Knepley ctx->mg = pc; 31741b6fd38SMatthew G. Knepley ctx->l = l; 3189566063dSJacob Faibussowitsch PetscCall(PCSetType(*cr, PCSHELL)); 3199566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(*cr, ctx)); 3209566063dSJacob Faibussowitsch PetscCall(PCShellSetApply(*cr, CRApply_Private)); 3219566063dSJacob Faibussowitsch PetscCall(PCShellSetSetUp(*cr, CRSetup_Private)); 3229566063dSJacob Faibussowitsch PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private)); 32341b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 32441b6fd38SMatthew G. Knepley } 32541b6fd38SMatthew G. Knepley 3269371c9d4SSatish Balay PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms) { 327f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 328ce94432eSBarry Smith MPI_Comm comm; 3293aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 33010eca3edSLisandro Dalcin PCMGType mgtype = mg->am; 33110167fecSBarry Smith PetscInt mgctype = (PetscInt)PC_MG_CYCLE_V; 332f3fbd535SBarry Smith PetscInt i; 333f3fbd535SBarry Smith PetscMPIInt size; 334f3fbd535SBarry Smith const char *prefix; 335f3fbd535SBarry Smith PC ipc; 3363aeaf226SBarry Smith PetscInt n; 3374b9ad928SBarry Smith 3384b9ad928SBarry Smith PetscFunctionBegin; 3390700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 340548767e0SJed Brown PetscValidLogicalCollectiveInt(pc, levels, 2); 341548767e0SJed Brown if (mg->nlevels == levels) PetscFunctionReturn(0); 3429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 3433aeaf226SBarry Smith if (mglevels) { 34410eca3edSLisandro Dalcin mgctype = mglevels[0]->cycles; 3453aeaf226SBarry Smith /* changing the number of levels so free up the previous stuff */ 3469566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 3473aeaf226SBarry Smith n = mglevels[0]->levels; 3483aeaf226SBarry Smith for (i = 0; i < n; i++) { 349*48a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 3509566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 3519566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 3529566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 3533aeaf226SBarry Smith } 3549566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 3553aeaf226SBarry Smith } 356f3fbd535SBarry Smith 357f3fbd535SBarry Smith mg->nlevels = levels; 358f3fbd535SBarry Smith 3599566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(levels, &mglevels)); 3609566063dSJacob Faibussowitsch PetscCall(PetscLogObjectMemory((PetscObject)pc, levels * (sizeof(PC_MG *)))); 361f3fbd535SBarry Smith 3629566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 363f3fbd535SBarry Smith 364a9db87a2SMatthew G Knepley mg->stageApply = 0; 365f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 3669566063dSJacob Faibussowitsch PetscCall(PetscNewLog(pc, &mglevels[i])); 3672fa5cd67SKarl Rupp 368f3fbd535SBarry Smith mglevels[i]->level = i; 369f3fbd535SBarry Smith mglevels[i]->levels = levels; 37010eca3edSLisandro Dalcin mglevels[i]->cycles = mgctype; 371336babb1SJed Brown mg->default_smoothu = 2; 372336babb1SJed Brown mg->default_smoothd = 2; 37363e6d426SJed Brown mglevels[i]->eventsmoothsetup = 0; 37463e6d426SJed Brown mglevels[i]->eventsmoothsolve = 0; 37563e6d426SJed Brown mglevels[i]->eventresidual = 0; 37663e6d426SJed Brown mglevels[i]->eventinterprestrict = 0; 377f3fbd535SBarry Smith 378f3fbd535SBarry Smith if (comms) comm = comms[i]; 379d5a8f7e6SBarry Smith if (comm != MPI_COMM_NULL) { 3809566063dSJacob Faibussowitsch PetscCall(KSPCreate(comm, &mglevels[i]->smoothd)); 3819566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure)); 3829566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i)); 3839566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix)); 3849566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level)); 3850ee9a668SBarry Smith if (i || levels == 1) { 3860ee9a668SBarry Smith char tprefix[128]; 3870ee9a668SBarry Smith 3889566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV)); 3899566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL)); 3909566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE)); 3919566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc)); 3929566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCSOR)); 3939566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd)); 394f3fbd535SBarry Smith 3959566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%d_", (int)i)); 3969566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 3970ee9a668SBarry Smith } else { 3989566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_")); 399f3fbd535SBarry Smith 4009dbfc187SHong Zhang /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 4019566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY)); 4029566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc)); 4039566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 404f3fbd535SBarry Smith if (size > 1) { 4059566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCREDUNDANT)); 406f3fbd535SBarry Smith } else { 4079566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCLU)); 408f3fbd535SBarry Smith } 4099566063dSJacob Faibussowitsch PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS)); 410f3fbd535SBarry Smith } 4119566063dSJacob Faibussowitsch PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mglevels[i]->smoothd)); 412d5a8f7e6SBarry Smith } 413f3fbd535SBarry Smith mglevels[i]->smoothu = mglevels[i]->smoothd; 41431567311SBarry Smith mg->rtol = 0.0; 41531567311SBarry Smith mg->abstol = 0.0; 41631567311SBarry Smith mg->dtol = 0.0; 41731567311SBarry Smith mg->ttol = 0.0; 41831567311SBarry Smith mg->cyclesperpcapply = 1; 419f3fbd535SBarry Smith } 420f3fbd535SBarry Smith mg->levels = mglevels; 4219566063dSJacob Faibussowitsch PetscCall(PCMGSetType(pc, mgtype)); 4224b9ad928SBarry Smith PetscFunctionReturn(0); 4234b9ad928SBarry Smith } 4244b9ad928SBarry Smith 42597d33e41SMatthew G. Knepley /*@C 42697d33e41SMatthew G. Knepley PCMGSetLevels - Sets the number of levels to use with MG. 42797d33e41SMatthew G. Knepley Must be called before any other MG routine. 42897d33e41SMatthew G. Knepley 42997d33e41SMatthew G. Knepley Logically Collective on PC 43097d33e41SMatthew G. Knepley 43197d33e41SMatthew G. Knepley Input Parameters: 43297d33e41SMatthew G. Knepley + pc - the preconditioner context 43397d33e41SMatthew G. Knepley . levels - the number of levels 43497d33e41SMatthew G. Knepley - comms - optional communicators for each level; this is to allow solving the coarser problems 435d5a8f7e6SBarry Smith on smaller sets of processes. For processes that are not included in the computation 43605552d4bSJunchao Zhang you must pass MPI_COMM_NULL. Use comms = NULL to specify that all processes 43705552d4bSJunchao Zhang should participate in each level of problem. 43897d33e41SMatthew G. Knepley 43997d33e41SMatthew G. Knepley Level: intermediate 44097d33e41SMatthew G. Knepley 44197d33e41SMatthew G. Knepley Notes: 44297d33e41SMatthew G. Knepley If the number of levels is one then the multigrid uses the -mg_levels prefix 44397d33e41SMatthew G. Knepley for setting the level options rather than the -mg_coarse prefix. 44497d33e41SMatthew G. Knepley 445d5a8f7e6SBarry Smith You can free the information in comms after this routine is called. 446d5a8f7e6SBarry Smith 447d5a8f7e6SBarry Smith The array of MPI communicators must contain MPI_COMM_NULL for those ranks that at each level 448d5a8f7e6SBarry Smith are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on 449d5a8f7e6SBarry Smith the two levels, rank 0 in the original communicator will pass in an array of 2 communicators 450d5a8f7e6SBarry Smith of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators 451d5a8f7e6SBarry Smith the first of size 2 and the second of value MPI_COMM_NULL since the rank 1 does not participate 452d5a8f7e6SBarry Smith in the coarse grid solve. 453d5a8f7e6SBarry Smith 454d5a8f7e6SBarry Smith Since each coarser level may have a new MPI_Comm with fewer ranks than the previous, one 455d5a8f7e6SBarry Smith must take special care in providing the restriction and interpolation operation. We recommend 456d5a8f7e6SBarry Smith providing these as two step operations; first perform a standard restriction or interpolation on 457d5a8f7e6SBarry Smith the full number of ranks for that level and then use an MPI call to copy the resulting vector 45805552d4bSJunchao Zhang array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both 459d5a8f7e6SBarry Smith cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and 460d5a8f7e6SBarry Smith recieves or MPI_AlltoAllv() could be used to do the reshuffling of the vector entries. 461d5a8f7e6SBarry Smith 46205552d4bSJunchao Zhang Fortran Notes: 46305552d4bSJunchao Zhang Use comms = PETSC_NULL_MPI_COMM as the equivalent of NULL in the C interface. Note PETSC_NULL_MPI_COMM 46405552d4bSJunchao Zhang is not MPI_COMM_NULL. It is more like PETSC_NULL_INTEGER, PETSC_NULL_REAL etc. 465d5a8f7e6SBarry Smith 466db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()` 46797d33e41SMatthew G. Knepley @*/ 4689371c9d4SSatish Balay PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) { 46997d33e41SMatthew G. Knepley PetscFunctionBegin; 47097d33e41SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 47197d33e41SMatthew G. Knepley if (comms) PetscValidPointer(comms, 3); 472cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms)); 47397d33e41SMatthew G. Knepley PetscFunctionReturn(0); 47497d33e41SMatthew G. Knepley } 47597d33e41SMatthew G. Knepley 4769371c9d4SSatish Balay PetscErrorCode PCDestroy_MG(PC pc) { 477a06653b4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 478a06653b4SBarry Smith PC_MG_Levels **mglevels = mg->levels; 479a06653b4SBarry Smith PetscInt i, n; 480c07bf074SBarry Smith 481c07bf074SBarry Smith PetscFunctionBegin; 4829566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 483a06653b4SBarry Smith if (mglevels) { 484a06653b4SBarry Smith n = mglevels[0]->levels; 485a06653b4SBarry Smith for (i = 0; i < n; i++) { 486*48a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 4879566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 4889566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 4899566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 490a06653b4SBarry Smith } 4919566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 492a06653b4SBarry Smith } 4939566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 4949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 4959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 4962b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL)); 4972b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL)); 4982b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL)); 4992b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5002b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5012b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL)); 5022b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL)); 5032b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL)); 5042b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL)); 5052b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL)); 5062b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL)); 507f3fbd535SBarry Smith PetscFunctionReturn(0); 508f3fbd535SBarry Smith } 509f3fbd535SBarry Smith 510f3fbd535SBarry Smith /* 511f3fbd535SBarry Smith PCApply_MG - Runs either an additive, multiplicative, Kaskadic 512f3fbd535SBarry Smith or full cycle of multigrid. 513f3fbd535SBarry Smith 514f3fbd535SBarry Smith Note: 515f3fbd535SBarry Smith A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 516f3fbd535SBarry Smith */ 5179371c9d4SSatish Balay static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) { 518f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 519f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 520391689abSStefano Zampini PC tpc; 521f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 52230b0564aSStefano Zampini PetscBool changeu, changed, matapp; 523f3fbd535SBarry Smith 524f3fbd535SBarry Smith PetscFunctionBegin; 52530b0564aSStefano Zampini matapp = (PetscBool)(B && X); 5269566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply)); 527e1d8e5deSBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 528298cc208SBarry Smith for (i = 0; i < levels; i++) { 529e1d8e5deSBarry Smith if (!mglevels[i]->A) { 5309566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 5319566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 532e1d8e5deSBarry Smith } 533e1d8e5deSBarry Smith } 534e1d8e5deSBarry Smith 5359566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 5369566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 5379566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 5389566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 539391689abSStefano Zampini if (!changeu && !changed) { 54030b0564aSStefano Zampini if (matapp) { 5419566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 54230b0564aSStefano Zampini mglevels[levels - 1]->B = B; 54330b0564aSStefano Zampini } else { 5449566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 545f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 54630b0564aSStefano Zampini } 547391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 54830b0564aSStefano Zampini if (matapp) { 54930b0564aSStefano Zampini if (mglevels[levels - 1]->B) { 55030b0564aSStefano Zampini PetscInt N1, N2; 55130b0564aSStefano Zampini PetscBool flg; 55230b0564aSStefano Zampini 5539566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1)); 5549566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N2)); 5559566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg)); 556*48a46eb9SPierre Jolivet if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 55730b0564aSStefano Zampini } 55830b0564aSStefano Zampini if (!mglevels[levels - 1]->B) { 5599566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B)); 56030b0564aSStefano Zampini } else { 5619566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN)); 56230b0564aSStefano Zampini } 56330b0564aSStefano Zampini } else { 564391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 565391689abSStefano Zampini Vec *vec; 566391689abSStefano Zampini 5679566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 568391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 5699566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 570391689abSStefano Zampini } 5719566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 572391689abSStefano Zampini } 57330b0564aSStefano Zampini } 5749371c9d4SSatish Balay if (matapp) { 5759371c9d4SSatish Balay mglevels[levels - 1]->X = X; 5769371c9d4SSatish Balay } else { 5779371c9d4SSatish Balay mglevels[levels - 1]->x = x; 5789371c9d4SSatish Balay } 57930b0564aSStefano Zampini 58030b0564aSStefano Zampini /* If coarser Xs are present, it means we have already block applied the PC at least once 58130b0564aSStefano Zampini Reset operators if sizes/type do no match */ 58230b0564aSStefano Zampini if (matapp && levels > 1 && mglevels[levels - 2]->X) { 58330b0564aSStefano Zampini PetscInt Xc, Bc; 58430b0564aSStefano Zampini PetscBool flg; 58530b0564aSStefano Zampini 5869566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc)); 5879566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc)); 5889566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg)); 58930b0564aSStefano Zampini if (Xc != Bc || !flg) { 5909566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->R)); 59130b0564aSStefano Zampini for (i = 0; i < levels - 1; i++) { 5929566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->R)); 5939566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 5949566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 59530b0564aSStefano Zampini } 59630b0564aSStefano Zampini } 59730b0564aSStefano Zampini } 598391689abSStefano Zampini 59931567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6009566063dSJacob Faibussowitsch if (matapp) PetscCall(MatZeroEntries(X)); 6019566063dSJacob Faibussowitsch else PetscCall(VecZeroEntries(x)); 602*48a46eb9SPierre Jolivet for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL)); 6032fa5cd67SKarl Rupp } else if (mg->am == PC_MG_ADDITIVE) { 6049566063dSJacob Faibussowitsch PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp)); 6052fa5cd67SKarl Rupp } else if (mg->am == PC_MG_KASKADE) { 6069566063dSJacob Faibussowitsch PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp)); 6072fa5cd67SKarl Rupp } else { 6089566063dSJacob Faibussowitsch PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp)); 609f3fbd535SBarry Smith } 6109566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePop()); 61130b0564aSStefano Zampini if (!changeu && !changed) { 6129371c9d4SSatish Balay if (matapp) { 6139371c9d4SSatish Balay mglevels[levels - 1]->B = NULL; 6149371c9d4SSatish Balay } else { 6159371c9d4SSatish Balay mglevels[levels - 1]->b = NULL; 6169371c9d4SSatish Balay } 61730b0564aSStefano Zampini } 618f3fbd535SBarry Smith PetscFunctionReturn(0); 619f3fbd535SBarry Smith } 620f3fbd535SBarry Smith 6219371c9d4SSatish Balay static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) { 622fcb023d4SJed Brown PetscFunctionBegin; 6239566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE)); 624fcb023d4SJed Brown PetscFunctionReturn(0); 625fcb023d4SJed Brown } 626fcb023d4SJed Brown 6279371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) { 628fcb023d4SJed Brown PetscFunctionBegin; 6299566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE)); 63030b0564aSStefano Zampini PetscFunctionReturn(0); 63130b0564aSStefano Zampini } 63230b0564aSStefano Zampini 6339371c9d4SSatish Balay static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) { 63430b0564aSStefano Zampini PetscFunctionBegin; 6359566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE)); 636fcb023d4SJed Brown PetscFunctionReturn(0); 637fcb023d4SJed Brown } 638f3fbd535SBarry Smith 6399371c9d4SSatish Balay PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject) { 640710315b6SLawrence Mitchell PetscInt levels, cycles; 641f3b08a26SMatthew G. Knepley PetscBool flg, flg2; 642f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 6433d3eaba7SBarry Smith PC_MG_Levels **mglevels; 644f3fbd535SBarry Smith PCMGType mgtype; 645f3fbd535SBarry Smith PCMGCycleType mgctype; 6462134b1e4SBarry Smith PCMGGalerkinType gtype; 6472b3cbbdaSStefano Zampini PCMGCoarseSpaceType coarseSpaceType; 648f3fbd535SBarry Smith 649f3fbd535SBarry Smith PetscFunctionBegin; 6501d743356SStefano Zampini levels = PetscMax(mg->nlevels, 1); 651d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options"); 6529566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg)); 6531a97d7b6SStefano Zampini if (!flg && !mg->levels && pc->dm) { 6549566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 655eb3f98d2SBarry Smith levels++; 6563aeaf226SBarry Smith mg->usedmfornumberoflevels = PETSC_TRUE; 657eb3f98d2SBarry Smith } 6589566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 6593aeaf226SBarry Smith mglevels = mg->levels; 6603aeaf226SBarry Smith 661f3fbd535SBarry Smith mgctype = (PCMGCycleType)mglevels[0]->cycles; 6629566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg)); 6631baa6e33SBarry Smith if (flg) PetscCall(PCMGSetCycleType(pc, mgctype)); 6642134b1e4SBarry Smith gtype = mg->galerkin; 6659566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)gtype, (PetscEnum *)>ype, &flg)); 6661baa6e33SBarry Smith if (flg) PetscCall(PCMGSetGalerkin(pc, gtype)); 6672b3cbbdaSStefano Zampini coarseSpaceType = mg->coarseSpaceType; 6682b3cbbdaSStefano Zampini PetscCall(PetscOptionsEnum("-pc_mg_adapt_interp_coarse_space", "Type of adaptive coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw", "PCMGSetAdaptCoarseSpaceType", PCMGCoarseSpaceTypes, (PetscEnum)coarseSpaceType, (PetscEnum *)&coarseSpaceType, &flg)); 6692b3cbbdaSStefano Zampini if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType)); 6709566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg)); 6719566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg)); 67241b6fd38SMatthew G. Knepley flg2 = PETSC_FALSE; 6739566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg)); 6749566063dSJacob Faibussowitsch if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2)); 675f56b1265SBarry Smith flg = PETSC_FALSE; 6769566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL)); 6771baa6e33SBarry Smith if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc)); 67831567311SBarry Smith mgtype = mg->am; 6799566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg)); 6801baa6e33SBarry Smith if (flg) PetscCall(PCMGSetType(pc, mgtype)); 68131567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6829566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg)); 6831baa6e33SBarry Smith if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles)); 684f3fbd535SBarry Smith } 685f3fbd535SBarry Smith flg = PETSC_FALSE; 6869566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL)); 687f3fbd535SBarry Smith if (flg) { 688f3fbd535SBarry Smith PetscInt i; 689f3fbd535SBarry Smith char eventname[128]; 6901a97d7b6SStefano Zampini 691f3fbd535SBarry Smith levels = mglevels[0]->levels; 692f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 693f3fbd535SBarry Smith sprintf(eventname, "MGSetup Level %d", (int)i); 6949566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup)); 695f3fbd535SBarry Smith sprintf(eventname, "MGSmooth Level %d", (int)i); 6969566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve)); 697f3fbd535SBarry Smith if (i) { 698f3fbd535SBarry Smith sprintf(eventname, "MGResid Level %d", (int)i); 6999566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual)); 700f3fbd535SBarry Smith sprintf(eventname, "MGInterp Level %d", (int)i); 7019566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict)); 702f3fbd535SBarry Smith } 703f3fbd535SBarry Smith } 704eec35531SMatthew G Knepley 705ec60ca73SSatish Balay #if defined(PETSC_USE_LOG) 706eec35531SMatthew G Knepley { 707eec35531SMatthew G Knepley const char *sname = "MG Apply"; 708eec35531SMatthew G Knepley PetscStageLog stageLog; 709eec35531SMatthew G Knepley PetscInt st; 710eec35531SMatthew G Knepley 7119566063dSJacob Faibussowitsch PetscCall(PetscLogGetStageLog(&stageLog)); 712eec35531SMatthew G Knepley for (st = 0; st < stageLog->numStages; ++st) { 713eec35531SMatthew G Knepley PetscBool same; 714eec35531SMatthew G Knepley 7159566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(stageLog->stageInfo[st].name, sname, &same)); 7162fa5cd67SKarl Rupp if (same) mg->stageApply = st; 717eec35531SMatthew G Knepley } 718*48a46eb9SPierre Jolivet if (!mg->stageApply) PetscCall(PetscLogStageRegister(sname, &mg->stageApply)); 719eec35531SMatthew G Knepley } 720ec60ca73SSatish Balay #endif 721f3fbd535SBarry Smith } 722d0609cedSBarry Smith PetscOptionsHeadEnd(); 723f3b08a26SMatthew G. Knepley /* Check option consistency */ 7249566063dSJacob Faibussowitsch PetscCall(PCMGGetGalerkin(pc, >ype)); 7259566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptInterpolation(pc, &flg)); 72608401ef6SPierre Jolivet PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator"); 727f3fbd535SBarry Smith PetscFunctionReturn(0); 728f3fbd535SBarry Smith } 729f3fbd535SBarry Smith 7300a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL}; 7310a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL}; 7320a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL}; 7332b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL}; 734f3fbd535SBarry Smith 7359804daf3SBarry Smith #include <petscdraw.h> 7369371c9d4SSatish Balay PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) { 737f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 738f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 739e3deeeafSJed Brown PetscInt levels = mglevels ? mglevels[0]->levels : 0, i; 740219b1045SBarry Smith PetscBool iascii, isbinary, isdraw; 741f3fbd535SBarry Smith 742f3fbd535SBarry Smith PetscFunctionBegin; 7439566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 7449566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 7459566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 746f3fbd535SBarry Smith if (iascii) { 747e3deeeafSJed Brown const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 74863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename)); 749*48a46eb9SPierre Jolivet if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply)); 7502134b1e4SBarry Smith if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 7519566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n")); 7522134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 7539566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n")); 7542134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 7559566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n")); 7562134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 7579566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n")); 7584f66f45eSBarry Smith } else { 7599566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n")); 760f3fbd535SBarry Smith } 7611baa6e33SBarry Smith if (mg->view) PetscCall((*mg->view)(pc, viewer)); 762f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 76363a3b9bcSJacob Faibussowitsch if (i) { 76463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 765f3fbd535SBarry Smith } else { 76663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 767f3fbd535SBarry Smith } 7689566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7699566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 7709566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 771f3fbd535SBarry Smith if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 7729566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n")); 773f3fbd535SBarry Smith } else if (i) { 77463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 7759566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7769566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 7779566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 778f3fbd535SBarry Smith } 77941b6fd38SMatthew G. Knepley if (i && mglevels[i]->cr) { 78063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i)); 7819566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7829566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->cr, viewer)); 7839566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 78441b6fd38SMatthew G. Knepley } 785f3fbd535SBarry Smith } 7865b0b0462SBarry Smith } else if (isbinary) { 7875b0b0462SBarry Smith for (i = levels - 1; i >= 0; i--) { 7889566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 789*48a46eb9SPierre Jolivet if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 7905b0b0462SBarry Smith } 791219b1045SBarry Smith } else if (isdraw) { 792219b1045SBarry Smith PetscDraw draw; 793b4375e8dSPeter Brune PetscReal x, w, y, bottom, th; 7949566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 7959566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 7969566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, NULL, &th)); 797219b1045SBarry Smith bottom = y - th; 798219b1045SBarry Smith for (i = levels - 1; i >= 0; i--) { 799b4375e8dSPeter Brune if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 8009566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 8019566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8029566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 803b4375e8dSPeter Brune } else { 804b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x); 8059566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 8069566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8079566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 8089566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 8099566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8109566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 811b4375e8dSPeter Brune } 8129566063dSJacob Faibussowitsch PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL)); 8131cd381d6SBarry Smith bottom -= th; 814219b1045SBarry Smith } 8155b0b0462SBarry Smith } 816f3fbd535SBarry Smith PetscFunctionReturn(0); 817f3fbd535SBarry Smith } 818f3fbd535SBarry Smith 819af0996ceSBarry Smith #include <petsc/private/kspimpl.h> 820cab2e9ccSBarry Smith 821f3fbd535SBarry Smith /* 822f3fbd535SBarry Smith Calls setup for the KSP on each level 823f3fbd535SBarry Smith */ 8249371c9d4SSatish Balay PetscErrorCode PCSetUp_MG(PC pc) { 825f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 826f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 8271a97d7b6SStefano Zampini PetscInt i, n; 82898e04984SBarry Smith PC cpc; 8293db492dfSBarry Smith PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE; 830f3fbd535SBarry Smith Mat dA, dB; 831f3fbd535SBarry Smith Vec tvec; 832218a07d4SBarry Smith DM *dms; 8330a545947SLisandro Dalcin PetscViewer viewer = NULL; 83441b6fd38SMatthew G. Knepley PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE; 8352b3cbbdaSStefano Zampini PetscBool adaptInterpolation = mg->adaptInterpolation; 836f3fbd535SBarry Smith 837f3fbd535SBarry Smith PetscFunctionBegin; 83828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up"); 8391a97d7b6SStefano Zampini n = mglevels[0]->levels; 84001bc414fSDmitry Karpeev /* FIX: Move this to PCSetFromOptions_MG? */ 8413aeaf226SBarry Smith if (mg->usedmfornumberoflevels) { 8423aeaf226SBarry Smith PetscInt levels; 8439566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 8443aeaf226SBarry Smith levels++; 8453aeaf226SBarry Smith if (levels > n) { /* the problem is now being solved on a finer grid */ 8469566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 8473aeaf226SBarry Smith n = levels; 8489566063dSJacob Faibussowitsch PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 8493aeaf226SBarry Smith mglevels = mg->levels; 8503aeaf226SBarry Smith } 8513aeaf226SBarry Smith } 8529566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc)); 8533aeaf226SBarry Smith 854f3fbd535SBarry Smith /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 855f3fbd535SBarry Smith /* so use those from global PC */ 856f3fbd535SBarry Smith /* Is this what we always want? What if user wants to keep old one? */ 8579566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset)); 85898e04984SBarry Smith if (opsset) { 85998e04984SBarry Smith Mat mmat; 8609566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat)); 86198e04984SBarry Smith if (mmat == pc->pmat) opsset = PETSC_FALSE; 86298e04984SBarry Smith } 8634a5f07a5SMark F. Adams 86441b6fd38SMatthew G. Knepley /* Create CR solvers */ 8659566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptCR(pc, &doCR)); 86641b6fd38SMatthew G. Knepley if (doCR) { 86741b6fd38SMatthew G. Knepley const char *prefix; 86841b6fd38SMatthew G. Knepley 8699566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 87041b6fd38SMatthew G. Knepley for (i = 1; i < n; ++i) { 87141b6fd38SMatthew G. Knepley PC ipc, cr; 87241b6fd38SMatthew G. Knepley char crprefix[128]; 87341b6fd38SMatthew G. Knepley 8749566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr)); 8759566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 8769566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i)); 8779566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 8789566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 8799566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 8809566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 8819566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 8829566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->cr, &ipc)); 88341b6fd38SMatthew G. Knepley 8849566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCCOMPOSITE)); 8859566063dSJacob Faibussowitsch PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 8869566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPCType(ipc, PCSOR)); 8879566063dSJacob Faibussowitsch PetscCall(CreateCR_Private(pc, i, &cr)); 8889566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPC(ipc, cr)); 8899566063dSJacob Faibussowitsch PetscCall(PCDestroy(&cr)); 89041b6fd38SMatthew G. Knepley 8919566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd)); 8929566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 8939566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int)i)); 8949566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 8959566063dSJacob Faibussowitsch PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mglevels[i]->cr)); 89641b6fd38SMatthew G. Knepley } 89741b6fd38SMatthew G. Knepley } 89841b6fd38SMatthew G. Knepley 8994a5f07a5SMark F. Adams if (!opsset) { 9009566063dSJacob Faibussowitsch PetscCall(PCGetUseAmat(pc, &use_amat)); 9014a5f07a5SMark F. Adams if (use_amat) { 9029566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n")); 9039566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat)); 90469858f1bSStefano Zampini } else { 9059566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Using matrix (pmat) operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n")); 9069566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat)); 9074a5f07a5SMark F. Adams } 9084a5f07a5SMark F. Adams } 909f3fbd535SBarry Smith 9109c7ffb39SBarry Smith for (i = n - 1; i > 0; i--) { 9119c7ffb39SBarry Smith if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 9129c7ffb39SBarry Smith missinginterpolate = PETSC_TRUE; 9132b3cbbdaSStefano Zampini break; 9149c7ffb39SBarry Smith } 9159c7ffb39SBarry Smith } 9162134b1e4SBarry Smith 9179566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB)); 9182134b1e4SBarry Smith if (dA == dB) dAeqdB = PETSC_TRUE; 9192b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) { 9202134b1e4SBarry Smith needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */ 9212134b1e4SBarry Smith } 9222134b1e4SBarry Smith 9232b3cbbdaSStefano Zampini if (pc->dm && !pc->setupcalled) { 9242b3cbbdaSStefano Zampini /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 9252b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm)); 9262b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE)); 9272b3cbbdaSStefano Zampini if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) { 9282b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm)); 9292b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE)); 9302b3cbbdaSStefano Zampini } 9312b3cbbdaSStefano Zampini if (mglevels[n - 1]->cr) { 9322b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm)); 9332b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE)); 9342b3cbbdaSStefano Zampini } 9352b3cbbdaSStefano Zampini } 9362b3cbbdaSStefano Zampini 9379c7ffb39SBarry Smith /* 9389c7ffb39SBarry Smith Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 9392b3cbbdaSStefano Zampini Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 9409c7ffb39SBarry Smith */ 94132fe681dSStefano Zampini if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 94232fe681dSStefano Zampini /* first see if we can compute a coarse space */ 94332fe681dSStefano Zampini if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) { 94432fe681dSStefano Zampini for (i = n - 2; i > -1; i--) { 94532fe681dSStefano Zampini if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) { 94632fe681dSStefano Zampini PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace)); 94732fe681dSStefano Zampini PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace)); 94832fe681dSStefano Zampini } 94932fe681dSStefano Zampini } 95032fe681dSStefano Zampini } else { /* construct the interpolation from the DMs */ 9512e499ae9SBarry Smith Mat p; 95273250ac0SBarry Smith Vec rscale; 9539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &dms)); 954218a07d4SBarry Smith dms[n - 1] = pc->dm; 955ef1267afSMatthew G. Knepley /* Separately create them so we do not get DMKSP interference between levels */ 9569566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i])); 957218a07d4SBarry Smith for (i = n - 2; i > -1; i--) { 958942e3340SBarry Smith DMKSP kdm; 959eab52d2bSLawrence Mitchell PetscBool dmhasrestrict, dmhasinject; 9609566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i])); 9619566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE)); 962c27ee7a3SPatrick Farrell if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 9639566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i])); 9649566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE)); 965c27ee7a3SPatrick Farrell } 96641b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 9679566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->cr, dms[i])); 9689566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE)); 96941b6fd38SMatthew G. Knepley } 9709566063dSJacob Faibussowitsch PetscCall(DMGetDMKSPWrite(dms[i], &kdm)); 971d1a3e677SJed Brown /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 972d1a3e677SJed Brown * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 9730298fd71SBarry Smith kdm->ops->computerhs = NULL; 9740298fd71SBarry Smith kdm->rhsctx = NULL; 97524c3aa18SBarry Smith if (!mglevels[i + 1]->interpolate) { 9769566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale)); 9779566063dSJacob Faibussowitsch PetscCall(PCMGSetInterpolation(pc, i + 1, p)); 9789566063dSJacob Faibussowitsch if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale)); 9799566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rscale)); 9809566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 981218a07d4SBarry Smith } 9829566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict)); 9833ad4599aSBarry Smith if (dmhasrestrict && !mglevels[i + 1]->restrct) { 9849566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p)); 9859566063dSJacob Faibussowitsch PetscCall(PCMGSetRestriction(pc, i + 1, p)); 9869566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 9873ad4599aSBarry Smith } 9889566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(dms[i], &dmhasinject)); 989eab52d2bSLawrence Mitchell if (dmhasinject && !mglevels[i + 1]->inject) { 9909566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p)); 9919566063dSJacob Faibussowitsch PetscCall(PCMGSetInjection(pc, i + 1, p)); 9929566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 993eab52d2bSLawrence Mitchell } 99424c3aa18SBarry Smith } 9952d2b81a6SBarry Smith 9969566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i])); 9979566063dSJacob Faibussowitsch PetscCall(PetscFree(dms)); 998ce4cda84SJed Brown } 99932fe681dSStefano Zampini } 1000cab2e9ccSBarry Smith 10012134b1e4SBarry Smith if (mg->galerkin < PC_MG_GALERKIN_NONE) { 10022134b1e4SBarry Smith Mat A, B; 10032134b1e4SBarry Smith PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE; 10042134b1e4SBarry Smith MatReuse reuse = MAT_INITIAL_MATRIX; 10052134b1e4SBarry Smith 10062b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE; 10072b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE; 10082134b1e4SBarry Smith if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 1009f3fbd535SBarry Smith for (i = n - 2; i > -1; i--) { 10107827d75bSBarry Smith PetscCheck(mglevels[i + 1]->restrct || mglevels[i + 1]->interpolate, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must provide interpolation or restriction for each MG level except level 0"); 1011*48a46eb9SPierre Jolivet if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct)); 1012*48a46eb9SPierre Jolivet if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate)); 1013*48a46eb9SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B)); 1014*48a46eb9SPierre Jolivet if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A)); 1015*48a46eb9SPierre Jolivet if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B)); 10162134b1e4SBarry Smith /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 10172134b1e4SBarry Smith if (!doA && dAeqdB) { 10189566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B)); 10192134b1e4SBarry Smith A = B; 10202134b1e4SBarry Smith } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 10219566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL)); 10229566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 1023b9367914SBarry Smith } 10242134b1e4SBarry Smith if (!doB && dAeqdB) { 10259566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A)); 10262134b1e4SBarry Smith B = A; 10272134b1e4SBarry Smith } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 10289566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B)); 10299566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 10307d537d92SJed Brown } 10312134b1e4SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 10329566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B)); 10339566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)A)); 10349566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)B)); 10352134b1e4SBarry Smith } 10362134b1e4SBarry Smith dA = A; 1037f3fbd535SBarry Smith dB = B; 1038f3fbd535SBarry Smith } 1039f3fbd535SBarry Smith } 1040f3b08a26SMatthew G. Knepley 1041f3b08a26SMatthew G. Knepley /* Adapt interpolation matrices */ 10422b3cbbdaSStefano Zampini if (adaptInterpolation) { 1043f3b08a26SMatthew G. Knepley for (i = 0; i < n; ++i) { 1044*48a46eb9SPierre Jolivet if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace)); 10452b3cbbdaSStefano Zampini if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace)); 1046f3b08a26SMatthew G. Knepley } 1047*48a46eb9SPierre Jolivet for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i)); 1048f3b08a26SMatthew G. Knepley } 1049f3b08a26SMatthew G. Knepley 10502134b1e4SBarry Smith if (needRestricts && pc->dm) { 1051caa4e7f2SJed Brown for (i = n - 2; i >= 0; i--) { 1052ccceb50cSJed Brown DM dmfine, dmcoarse; 1053caa4e7f2SJed Brown Mat Restrict, Inject; 1054caa4e7f2SJed Brown Vec rscale; 10559566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine)); 10569566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse)); 10579566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict)); 10589566063dSJacob Faibussowitsch PetscCall(PCMGGetRScale(pc, i + 1, &rscale)); 10599566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(pc, i + 1, &Inject)); 10609566063dSJacob Faibussowitsch PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse)); 1061caa4e7f2SJed Brown } 1062caa4e7f2SJed Brown } 1063f3fbd535SBarry Smith 1064f3fbd535SBarry Smith if (!pc->setupcalled) { 1065*48a46eb9SPierre Jolivet for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd)); 1066f3fbd535SBarry Smith for (i = 1; i < n; i++) { 1067*48a46eb9SPierre Jolivet if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu)); 1068*48a46eb9SPierre Jolivet if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr)); 1069f3fbd535SBarry Smith } 10703ad4599aSBarry Smith /* insure that if either interpolation or restriction is set the other other one is set */ 1071f3fbd535SBarry Smith for (i = 1; i < n; i++) { 10729566063dSJacob Faibussowitsch PetscCall(PCMGGetInterpolation(pc, i, NULL)); 10739566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i, NULL)); 1074f3fbd535SBarry Smith } 1075f3fbd535SBarry Smith for (i = 0; i < n - 1; i++) { 1076f3fbd535SBarry Smith if (!mglevels[i]->b) { 1077f3fbd535SBarry Smith Vec *vec; 10789566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL)); 10799566063dSJacob Faibussowitsch PetscCall(PCMGSetRhs(pc, i, *vec)); 10809566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 10819566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1082f3fbd535SBarry Smith } 1083f3fbd535SBarry Smith if (!mglevels[i]->r && i) { 10849566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 10859566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, i, tvec)); 10869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1087f3fbd535SBarry Smith } 1088f3fbd535SBarry Smith if (!mglevels[i]->x) { 10899566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 10909566063dSJacob Faibussowitsch PetscCall(PCMGSetX(pc, i, tvec)); 10919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1092f3fbd535SBarry Smith } 109341b6fd38SMatthew G. Knepley if (doCR) { 10949566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx)); 10959566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb)); 10969566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[i]->crb)); 109741b6fd38SMatthew G. Knepley } 1098f3fbd535SBarry Smith } 1099f3fbd535SBarry Smith if (n != 1 && !mglevels[n - 1]->r) { 1100f3fbd535SBarry Smith /* PCMGSetR() on the finest level if user did not supply it */ 1101f3fbd535SBarry Smith Vec *vec; 11029566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL)); 11039566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, n - 1, *vec)); 11049566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11059566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1106f3fbd535SBarry Smith } 110741b6fd38SMatthew G. Knepley if (doCR) { 11089566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx)); 11099566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb)); 11109566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[n - 1]->crb)); 111141b6fd38SMatthew G. Knepley } 1112f3fbd535SBarry Smith } 1113f3fbd535SBarry Smith 111498e04984SBarry Smith if (pc->dm) { 111598e04984SBarry Smith /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 111698e04984SBarry Smith for (i = 0; i < n - 1; i++) { 111798e04984SBarry Smith if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 111898e04984SBarry Smith } 111998e04984SBarry Smith } 112008549ed4SJed Brown // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g., 112108549ed4SJed Brown // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply. 112208549ed4SJed Brown if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1123f3fbd535SBarry Smith 1124f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11252a21e185SBarry Smith if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1126f3fbd535SBarry Smith /* if doing only down then initial guess is zero */ 11279566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1128f3fbd535SBarry Smith } 11299566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11309566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11319566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothd)); 11329371c9d4SSatish Balay if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; } 11339566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1134d42688cbSBarry Smith if (!mglevels[i]->residual) { 1135d42688cbSBarry Smith Mat mat; 11369566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11379566063dSJacob Faibussowitsch PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat)); 1138d42688cbSBarry Smith } 1139fcb023d4SJed Brown if (!mglevels[i]->residualtranspose) { 1140fcb023d4SJed Brown Mat mat; 11419566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11429566063dSJacob Faibussowitsch PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat)); 1143fcb023d4SJed Brown } 1144f3fbd535SBarry Smith } 1145f3fbd535SBarry Smith for (i = 1; i < n; i++) { 1146f3fbd535SBarry Smith if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1147f3fbd535SBarry Smith Mat downmat, downpmat; 1148f3fbd535SBarry Smith 1149f3fbd535SBarry Smith /* check if operators have been set for up, if not use down operators to set them */ 11509566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL)); 1151f3fbd535SBarry Smith if (!opsset) { 11529566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11539566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat)); 1154f3fbd535SBarry Smith } 1155f3fbd535SBarry Smith 11569566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE)); 11579566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11589566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothu)); 11599371c9d4SSatish Balay if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; } 11609566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1161f3fbd535SBarry Smith } 116241b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 116341b6fd38SMatthew G. Knepley Mat downmat, downpmat; 116441b6fd38SMatthew G. Knepley 116541b6fd38SMatthew G. Knepley /* check if operators have been set for up, if not use down operators to set them */ 11669566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL)); 116741b6fd38SMatthew G. Knepley if (!opsset) { 11689566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11699566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat)); 117041b6fd38SMatthew G. Knepley } 117141b6fd38SMatthew G. Knepley 11729566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11739566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11749566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->cr)); 11759371c9d4SSatish Balay if (mglevels[i]->cr->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; } 11769566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 117741b6fd38SMatthew G. Knepley } 1178f3fbd535SBarry Smith } 1179f3fbd535SBarry Smith 11809566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 11819566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[0]->smoothd)); 11829371c9d4SSatish Balay if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; } 11839566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1184f3fbd535SBarry Smith 1185f3fbd535SBarry Smith /* 1186f3fbd535SBarry Smith Dump the interpolation/restriction matrices plus the 1187e3c5b3baSBarry Smith Jacobian/stiffness on each level. This allows MATLAB users to 1188f3fbd535SBarry Smith easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1189f3fbd535SBarry Smith 1190f3fbd535SBarry Smith Only support one or the other at the same time. 1191f3fbd535SBarry Smith */ 1192f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER) 11939566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL)); 1194ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1195f3fbd535SBarry Smith dump = PETSC_FALSE; 1196f3fbd535SBarry Smith #endif 11979566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL)); 1198ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1199f3fbd535SBarry Smith 1200f3fbd535SBarry Smith if (viewer) { 1201*48a46eb9SPierre Jolivet for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer)); 1202f3fbd535SBarry Smith for (i = 0; i < n; i++) { 12039566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc)); 12049566063dSJacob Faibussowitsch PetscCall(MatView(pc->mat, viewer)); 1205f3fbd535SBarry Smith } 1206f3fbd535SBarry Smith } 1207f3fbd535SBarry Smith PetscFunctionReturn(0); 1208f3fbd535SBarry Smith } 1209f3fbd535SBarry Smith 1210f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/ 1211f3fbd535SBarry Smith 12129371c9d4SSatish Balay PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) { 121397d33e41SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 121497d33e41SMatthew G. Knepley 121597d33e41SMatthew G. Knepley PetscFunctionBegin; 121697d33e41SMatthew G. Knepley *levels = mg->nlevels; 121797d33e41SMatthew G. Knepley PetscFunctionReturn(0); 121897d33e41SMatthew G. Knepley } 121997d33e41SMatthew G. Knepley 12204b9ad928SBarry Smith /*@ 122197177400SBarry Smith PCMGGetLevels - Gets the number of levels to use with MG. 12224b9ad928SBarry Smith 12234b9ad928SBarry Smith Not Collective 12244b9ad928SBarry Smith 12254b9ad928SBarry Smith Input Parameter: 12264b9ad928SBarry Smith . pc - the preconditioner context 12274b9ad928SBarry Smith 12284b9ad928SBarry Smith Output parameter: 12294b9ad928SBarry Smith . levels - the number of levels 12304b9ad928SBarry Smith 12314b9ad928SBarry Smith Level: advanced 12324b9ad928SBarry Smith 1233db781477SPatrick Sanan .seealso: `PCMGSetLevels()` 12344b9ad928SBarry Smith @*/ 12359371c9d4SSatish Balay PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) { 12364b9ad928SBarry Smith PetscFunctionBegin; 12370700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 12384482741eSBarry Smith PetscValidIntPointer(levels, 2); 123997d33e41SMatthew G. Knepley *levels = 0; 1240cac4c232SBarry Smith PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels)); 12414b9ad928SBarry Smith PetscFunctionReturn(0); 12424b9ad928SBarry Smith } 12434b9ad928SBarry Smith 12444b9ad928SBarry Smith /*@ 1245e7d4b4cbSMark Adams PCMGGetGridComplexity - compute operator and grid complexity of MG hierarchy 1246e7d4b4cbSMark Adams 1247e7d4b4cbSMark Adams Input Parameter: 1248e7d4b4cbSMark Adams . pc - the preconditioner context 1249e7d4b4cbSMark Adams 125090db8557SMark Adams Output Parameters: 125190db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0 125290db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0 1253e7d4b4cbSMark Adams 1254e7d4b4cbSMark Adams Level: advanced 1255e7d4b4cbSMark Adams 1256db781477SPatrick Sanan .seealso: `PCMGGetLevels()` 1257e7d4b4cbSMark Adams @*/ 12589371c9d4SSatish Balay PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) { 1259e7d4b4cbSMark Adams PC_MG *mg = (PC_MG *)pc->data; 1260e7d4b4cbSMark Adams PC_MG_Levels **mglevels = mg->levels; 1261e7d4b4cbSMark Adams PetscInt lev, N; 1262e7d4b4cbSMark Adams PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1263e7d4b4cbSMark Adams MatInfo info; 1264e7d4b4cbSMark Adams 1265e7d4b4cbSMark Adams PetscFunctionBegin; 126690db8557SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 126790db8557SMark Adams if (gc) PetscValidRealPointer(gc, 2); 126890db8557SMark Adams if (oc) PetscValidRealPointer(oc, 3); 1269e7d4b4cbSMark Adams if (!pc->setupcalled) { 127090db8557SMark Adams if (gc) *gc = 0; 127190db8557SMark Adams if (oc) *oc = 0; 1272e7d4b4cbSMark Adams PetscFunctionReturn(0); 1273e7d4b4cbSMark Adams } 1274e7d4b4cbSMark Adams PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels"); 1275e7d4b4cbSMark Adams for (lev = 0; lev < mg->nlevels; lev++) { 1276e7d4b4cbSMark Adams Mat dB; 12779566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB)); 12789566063dSJacob Faibussowitsch PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */ 12799566063dSJacob Faibussowitsch PetscCall(MatGetSize(dB, &N, NULL)); 1280e7d4b4cbSMark Adams sgc += N; 1281e7d4b4cbSMark Adams soc += info.nz_used; 12829371c9d4SSatish Balay if (lev == mg->nlevels - 1) { 12839371c9d4SSatish Balay nnz0 = info.nz_used; 12849371c9d4SSatish Balay n0 = N; 12859371c9d4SSatish Balay } 1286e7d4b4cbSMark Adams } 128790db8557SMark Adams if (n0 > 0 && gc) *gc = (PetscReal)(sgc / n0); 1288e7d4b4cbSMark Adams else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available"); 128990db8557SMark Adams if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0); 1290e7d4b4cbSMark Adams PetscFunctionReturn(0); 1291e7d4b4cbSMark Adams } 1292e7d4b4cbSMark Adams 1293e7d4b4cbSMark Adams /*@ 129497177400SBarry Smith PCMGSetType - Determines the form of multigrid to use: 12954b9ad928SBarry Smith multiplicative, additive, full, or the Kaskade algorithm. 12964b9ad928SBarry Smith 1297ad4df100SBarry Smith Logically Collective on PC 12984b9ad928SBarry Smith 12994b9ad928SBarry Smith Input Parameters: 13004b9ad928SBarry Smith + pc - the preconditioner context 13019dcbbd2bSBarry Smith - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 13029dcbbd2bSBarry Smith PC_MG_FULL, PC_MG_KASKADE 13034b9ad928SBarry Smith 13044b9ad928SBarry Smith Options Database Key: 13054b9ad928SBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, 13064b9ad928SBarry Smith additive, full, kaskade 13074b9ad928SBarry Smith 13084b9ad928SBarry Smith Level: advanced 13094b9ad928SBarry Smith 1310db781477SPatrick Sanan .seealso: `PCMGSetLevels()` 13114b9ad928SBarry Smith @*/ 13129371c9d4SSatish Balay PetscErrorCode PCMGSetType(PC pc, PCMGType form) { 1313f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 13144b9ad928SBarry Smith 13154b9ad928SBarry Smith PetscFunctionBegin; 13160700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1317c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc, form, 2); 131831567311SBarry Smith mg->am = form; 13199dcbbd2bSBarry Smith if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1320c60c7ad4SBarry Smith else pc->ops->applyrichardson = NULL; 1321c60c7ad4SBarry Smith PetscFunctionReturn(0); 1322c60c7ad4SBarry Smith } 1323c60c7ad4SBarry Smith 1324c60c7ad4SBarry Smith /*@ 1325c60c7ad4SBarry Smith PCMGGetType - Determines the form of multigrid to use: 1326c60c7ad4SBarry Smith multiplicative, additive, full, or the Kaskade algorithm. 1327c60c7ad4SBarry Smith 1328c60c7ad4SBarry Smith Logically Collective on PC 1329c60c7ad4SBarry Smith 1330c60c7ad4SBarry Smith Input Parameter: 1331c60c7ad4SBarry Smith . pc - the preconditioner context 1332c60c7ad4SBarry Smith 1333c60c7ad4SBarry Smith Output Parameter: 1334c60c7ad4SBarry Smith . type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE 1335c60c7ad4SBarry Smith 1336c60c7ad4SBarry Smith Level: advanced 1337c60c7ad4SBarry Smith 1338db781477SPatrick Sanan .seealso: `PCMGSetLevels()` 1339c60c7ad4SBarry Smith @*/ 13409371c9d4SSatish Balay PetscErrorCode PCMGGetType(PC pc, PCMGType *type) { 1341c60c7ad4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1342c60c7ad4SBarry Smith 1343c60c7ad4SBarry Smith PetscFunctionBegin; 1344c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1345c60c7ad4SBarry Smith *type = mg->am; 13464b9ad928SBarry Smith PetscFunctionReturn(0); 13474b9ad928SBarry Smith } 13484b9ad928SBarry Smith 13494b9ad928SBarry Smith /*@ 13500d353602SBarry Smith PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 13514b9ad928SBarry Smith complicated cycling. 13524b9ad928SBarry Smith 1353ad4df100SBarry Smith Logically Collective on PC 13544b9ad928SBarry Smith 13554b9ad928SBarry Smith Input Parameters: 1356c2be2410SBarry Smith + pc - the multigrid context 1357c1cbb1deSBarry Smith - n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W 13584b9ad928SBarry Smith 13594b9ad928SBarry Smith Options Database Key: 1360c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired 13614b9ad928SBarry Smith 13624b9ad928SBarry Smith Level: advanced 13634b9ad928SBarry Smith 1364db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()` 13654b9ad928SBarry Smith @*/ 13669371c9d4SSatish Balay PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) { 1367f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1368f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 136979416396SBarry Smith PetscInt i, levels; 13704b9ad928SBarry Smith 13714b9ad928SBarry Smith PetscFunctionBegin; 13720700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 137369fbec6eSBarry Smith PetscValidLogicalCollectiveEnum(pc, n, 2); 137428b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1375f3fbd535SBarry Smith levels = mglevels[0]->levels; 13762fa5cd67SKarl Rupp for (i = 0; i < levels; i++) mglevels[i]->cycles = n; 13774b9ad928SBarry Smith PetscFunctionReturn(0); 13784b9ad928SBarry Smith } 13794b9ad928SBarry Smith 13808cc2d5dfSBarry Smith /*@ 13818cc2d5dfSBarry Smith PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 13828cc2d5dfSBarry Smith of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 13838cc2d5dfSBarry Smith 1384ad4df100SBarry Smith Logically Collective on PC 13858cc2d5dfSBarry Smith 13868cc2d5dfSBarry Smith Input Parameters: 13878cc2d5dfSBarry Smith + pc - the multigrid context 13888cc2d5dfSBarry Smith - n - number of cycles (default is 1) 13898cc2d5dfSBarry Smith 13908cc2d5dfSBarry Smith Options Database Key: 1391147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles 13928cc2d5dfSBarry Smith 13938cc2d5dfSBarry Smith Level: advanced 13948cc2d5dfSBarry Smith 139595452b02SPatrick Sanan Notes: 139695452b02SPatrick Sanan This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 13978cc2d5dfSBarry Smith 1398db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()` 13998cc2d5dfSBarry Smith @*/ 14009371c9d4SSatish Balay PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) { 1401f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14028cc2d5dfSBarry Smith 14038cc2d5dfSBarry Smith PetscFunctionBegin; 14040700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1405c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 14062a21e185SBarry Smith mg->cyclesperpcapply = n; 14078cc2d5dfSBarry Smith PetscFunctionReturn(0); 14088cc2d5dfSBarry Smith } 14098cc2d5dfSBarry Smith 14109371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) { 1411fb15c04eSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1412fb15c04eSBarry Smith 1413fb15c04eSBarry Smith PetscFunctionBegin; 14142134b1e4SBarry Smith mg->galerkin = use; 1415fb15c04eSBarry Smith PetscFunctionReturn(0); 1416fb15c04eSBarry Smith } 1417fb15c04eSBarry Smith 1418c2be2410SBarry Smith /*@ 141997177400SBarry Smith PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 142082b87d87SMatthew G. Knepley finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1421c2be2410SBarry Smith 1422ad4df100SBarry Smith Logically Collective on PC 1423c2be2410SBarry Smith 1424c2be2410SBarry Smith Input Parameters: 1425c91913d3SJed Brown + pc - the multigrid context 14262134b1e4SBarry Smith - use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE 1427c2be2410SBarry Smith 1428c2be2410SBarry Smith Options Database Key: 1429147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1430c2be2410SBarry Smith 1431c2be2410SBarry Smith Level: intermediate 1432c2be2410SBarry Smith 143395452b02SPatrick Sanan Notes: 143495452b02SPatrick Sanan Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not 14351c1aac46SBarry Smith use the PCMG construction of the coarser grids. 14361c1aac46SBarry Smith 1437db781477SPatrick Sanan .seealso: `PCMGGetGalerkin()`, `PCMGGalerkinType` 14383fc8bf9cSBarry Smith 1439c2be2410SBarry Smith @*/ 14409371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) { 1441c2be2410SBarry Smith PetscFunctionBegin; 14420700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1443cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use)); 1444c2be2410SBarry Smith PetscFunctionReturn(0); 1445c2be2410SBarry Smith } 1446c2be2410SBarry Smith 14473fc8bf9cSBarry Smith /*@ 14483fc8bf9cSBarry Smith PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 144982b87d87SMatthew G. Knepley A_i-1 = r_i * A_i * p_i 14503fc8bf9cSBarry Smith 14513fc8bf9cSBarry Smith Not Collective 14523fc8bf9cSBarry Smith 14533fc8bf9cSBarry Smith Input Parameter: 14543fc8bf9cSBarry Smith . pc - the multigrid context 14553fc8bf9cSBarry Smith 14563fc8bf9cSBarry Smith Output Parameter: 14572134b1e4SBarry Smith . galerkin - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, PC_MG_GALERKIN_NONE, or PC_MG_GALERKIN_EXTERNAL 14583fc8bf9cSBarry Smith 14593fc8bf9cSBarry Smith Level: intermediate 14603fc8bf9cSBarry Smith 1461db781477SPatrick Sanan .seealso: `PCMGSetGalerkin()`, `PCMGGalerkinType` 14623fc8bf9cSBarry Smith 14633fc8bf9cSBarry Smith @*/ 14649371c9d4SSatish Balay PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) { 1465f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14663fc8bf9cSBarry Smith 14673fc8bf9cSBarry Smith PetscFunctionBegin; 14680700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 14692134b1e4SBarry Smith *galerkin = mg->galerkin; 14703fc8bf9cSBarry Smith PetscFunctionReturn(0); 14713fc8bf9cSBarry Smith } 14723fc8bf9cSBarry Smith 14739371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) { 1474f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1475f3b08a26SMatthew G. Knepley 1476f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1477f3b08a26SMatthew G. Knepley mg->adaptInterpolation = adapt; 1478f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1479f3b08a26SMatthew G. Knepley } 1480f3b08a26SMatthew G. Knepley 14819371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) { 1482f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1483f3b08a26SMatthew G. Knepley 1484f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1485f3b08a26SMatthew G. Knepley *adapt = mg->adaptInterpolation; 1486f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1487f3b08a26SMatthew G. Knepley } 1488f3b08a26SMatthew G. Knepley 14899371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) { 14902b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 14912b3cbbdaSStefano Zampini 14922b3cbbdaSStefano Zampini PetscFunctionBegin; 14932b3cbbdaSStefano Zampini mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE; 14942b3cbbdaSStefano Zampini mg->coarseSpaceType = ctype; 14952b3cbbdaSStefano Zampini PetscFunctionReturn(0); 14962b3cbbdaSStefano Zampini } 14972b3cbbdaSStefano Zampini 14989371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) { 14992b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15002b3cbbdaSStefano Zampini 15012b3cbbdaSStefano Zampini PetscFunctionBegin; 15022b3cbbdaSStefano Zampini *ctype = mg->coarseSpaceType; 15032b3cbbdaSStefano Zampini PetscFunctionReturn(0); 15042b3cbbdaSStefano Zampini } 15052b3cbbdaSStefano Zampini 15069371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) { 150741b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 150841b6fd38SMatthew G. Knepley 150941b6fd38SMatthew G. Knepley PetscFunctionBegin; 151041b6fd38SMatthew G. Knepley mg->compatibleRelaxation = cr; 151141b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 151241b6fd38SMatthew G. Knepley } 151341b6fd38SMatthew G. Knepley 15149371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) { 151541b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 151641b6fd38SMatthew G. Knepley 151741b6fd38SMatthew G. Knepley PetscFunctionBegin; 151841b6fd38SMatthew G. Knepley *cr = mg->compatibleRelaxation; 151941b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 152041b6fd38SMatthew G. Knepley } 152141b6fd38SMatthew G. Knepley 15222b3cbbdaSStefano Zampini /*@C 15232b3cbbdaSStefano Zampini PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space. 15242b3cbbdaSStefano Zampini 15252b3cbbdaSStefano Zampini Adapts or creates the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 15262b3cbbdaSStefano Zampini 15272b3cbbdaSStefano Zampini Logically Collective on PC 15282b3cbbdaSStefano Zampini 15292b3cbbdaSStefano Zampini Input Parameters: 15302b3cbbdaSStefano Zampini + pc - the multigrid context 15312b3cbbdaSStefano Zampini - ctype - the type of coarse space 15322b3cbbdaSStefano Zampini 15332b3cbbdaSStefano Zampini Options Database Keys: 15342b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int> - The number of modes to use 15352b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw 15362b3cbbdaSStefano Zampini 15372b3cbbdaSStefano Zampini Level: intermediate 15382b3cbbdaSStefano Zampini 15392b3cbbdaSStefano Zampini .keywords: MG, set, Galerkin 15402b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()` 15412b3cbbdaSStefano Zampini @*/ 15429371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) { 15432b3cbbdaSStefano Zampini PetscFunctionBegin; 15442b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15452b3cbbdaSStefano Zampini PetscValidLogicalCollectiveEnum(pc, ctype, 2); 15462b3cbbdaSStefano Zampini PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype)); 15472b3cbbdaSStefano Zampini PetscFunctionReturn(0); 15482b3cbbdaSStefano Zampini } 15492b3cbbdaSStefano Zampini 15502b3cbbdaSStefano Zampini /*@C 15512b3cbbdaSStefano Zampini PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space. 15522b3cbbdaSStefano Zampini 15532b3cbbdaSStefano Zampini Not Collective 15542b3cbbdaSStefano Zampini 15552b3cbbdaSStefano Zampini Input Parameter: 15562b3cbbdaSStefano Zampini . pc - the multigrid context 15572b3cbbdaSStefano Zampini 15582b3cbbdaSStefano Zampini Output Parameter: 15592b3cbbdaSStefano Zampini . ctype - the type of coarse space 15602b3cbbdaSStefano Zampini 15612b3cbbdaSStefano Zampini Level: intermediate 15622b3cbbdaSStefano Zampini 15632b3cbbdaSStefano Zampini .keywords: MG, Get, Galerkin 15642b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()` 15652b3cbbdaSStefano Zampini @*/ 15669371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) { 15672b3cbbdaSStefano Zampini PetscFunctionBegin; 15682b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15692b3cbbdaSStefano Zampini PetscValidPointer(ctype, 2); 15702b3cbbdaSStefano Zampini PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype)); 15712b3cbbdaSStefano Zampini PetscFunctionReturn(0); 15722b3cbbdaSStefano Zampini } 15732b3cbbdaSStefano Zampini 15742b3cbbdaSStefano Zampini /* MATT: REMOVE? */ 1575f3b08a26SMatthew G. Knepley /*@ 1576f3b08a26SMatthew G. Knepley PCMGSetAdaptInterpolation - Adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 1577f3b08a26SMatthew G. Knepley 1578f3b08a26SMatthew G. Knepley Logically Collective on PC 1579f3b08a26SMatthew G. Knepley 1580f3b08a26SMatthew G. Knepley Input Parameters: 1581f3b08a26SMatthew G. Knepley + pc - the multigrid context 1582f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator 1583f3b08a26SMatthew G. Knepley 1584f3b08a26SMatthew G. Knepley Options Database Keys: 1585f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp - Turn on adaptation 1586f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1587f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1588f3b08a26SMatthew G. Knepley 1589f3b08a26SMatthew G. Knepley Level: intermediate 1590f3b08a26SMatthew G. Knepley 1591f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin 1592db781477SPatrick Sanan .seealso: `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()` 1593f3b08a26SMatthew G. Knepley @*/ 15949371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) { 1595f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1596f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1597cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt)); 1598f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1599f3b08a26SMatthew G. Knepley } 1600f3b08a26SMatthew G. Knepley 1601f3b08a26SMatthew G. Knepley /*@ 1602f3b08a26SMatthew G. Knepley PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 1603f3b08a26SMatthew G. Knepley 1604f3b08a26SMatthew G. Knepley Not collective 1605f3b08a26SMatthew G. Knepley 1606f3b08a26SMatthew G. Knepley Input Parameter: 1607f3b08a26SMatthew G. Knepley . pc - the multigrid context 1608f3b08a26SMatthew G. Knepley 1609f3b08a26SMatthew G. Knepley Output Parameter: 1610f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator 1611f3b08a26SMatthew G. Knepley 1612f3b08a26SMatthew G. Knepley Level: intermediate 1613f3b08a26SMatthew G. Knepley 1614f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin 1615db781477SPatrick Sanan .seealso: `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()` 1616f3b08a26SMatthew G. Knepley @*/ 16179371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) { 1618f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1619f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1620dadcf809SJacob Faibussowitsch PetscValidBoolPointer(adapt, 2); 1621cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt)); 1622f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1623f3b08a26SMatthew G. Knepley } 1624f3b08a26SMatthew G. Knepley 16254b9ad928SBarry Smith /*@ 162641b6fd38SMatthew G. Knepley PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 162741b6fd38SMatthew G. Knepley 162841b6fd38SMatthew G. Knepley Logically Collective on PC 162941b6fd38SMatthew G. Knepley 163041b6fd38SMatthew G. Knepley Input Parameters: 163141b6fd38SMatthew G. Knepley + pc - the multigrid context 163241b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation 163341b6fd38SMatthew G. Knepley 163441b6fd38SMatthew G. Knepley Options Database Keys: 163541b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation 163641b6fd38SMatthew G. Knepley 163741b6fd38SMatthew G. Knepley Level: intermediate 163841b6fd38SMatthew G. Knepley 163941b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin 1640db781477SPatrick Sanan .seealso: `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()` 164141b6fd38SMatthew G. Knepley @*/ 16429371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) { 164341b6fd38SMatthew G. Knepley PetscFunctionBegin; 164441b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1645cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr)); 164641b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 164741b6fd38SMatthew G. Knepley } 164841b6fd38SMatthew G. Knepley 164941b6fd38SMatthew G. Knepley /*@ 165041b6fd38SMatthew G. Knepley PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 165141b6fd38SMatthew G. Knepley 165241b6fd38SMatthew G. Knepley Not collective 165341b6fd38SMatthew G. Knepley 165441b6fd38SMatthew G. Knepley Input Parameter: 165541b6fd38SMatthew G. Knepley . pc - the multigrid context 165641b6fd38SMatthew G. Knepley 165741b6fd38SMatthew G. Knepley Output Parameter: 165841b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion 165941b6fd38SMatthew G. Knepley 166041b6fd38SMatthew G. Knepley Level: intermediate 166141b6fd38SMatthew G. Knepley 166241b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin 1663db781477SPatrick Sanan .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()` 166441b6fd38SMatthew G. Knepley @*/ 16659371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) { 166641b6fd38SMatthew G. Knepley PetscFunctionBegin; 166741b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1668dadcf809SJacob Faibussowitsch PetscValidBoolPointer(cr, 2); 1669cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr)); 167041b6fd38SMatthew G. Knepley PetscFunctionReturn(0); 167141b6fd38SMatthew G. Knepley } 167241b6fd38SMatthew G. Knepley 167341b6fd38SMatthew G. Knepley /*@ 167406792cafSBarry Smith PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1675710315b6SLawrence Mitchell on all levels. Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of 1676710315b6SLawrence Mitchell pre- and post-smoothing steps. 167706792cafSBarry Smith 167806792cafSBarry Smith Logically Collective on PC 167906792cafSBarry Smith 168006792cafSBarry Smith Input Parameters: 168106792cafSBarry Smith + mg - the multigrid context 168206792cafSBarry Smith - n - the number of smoothing steps 168306792cafSBarry Smith 168406792cafSBarry Smith Options Database Key: 1685a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 168606792cafSBarry Smith 168706792cafSBarry Smith Level: advanced 168806792cafSBarry Smith 168995452b02SPatrick Sanan Notes: 169095452b02SPatrick Sanan this does not set a value on the coarsest grid, since we assume that 169106792cafSBarry Smith there is no separate smooth up on the coarsest grid. 169206792cafSBarry Smith 1693db781477SPatrick Sanan .seealso: `PCMGSetDistinctSmoothUp()` 169406792cafSBarry Smith @*/ 16959371c9d4SSatish Balay PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) { 169606792cafSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 169706792cafSBarry Smith PC_MG_Levels **mglevels = mg->levels; 169806792cafSBarry Smith PetscInt i, levels; 169906792cafSBarry Smith 170006792cafSBarry Smith PetscFunctionBegin; 170106792cafSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 170206792cafSBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 170328b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 170406792cafSBarry Smith levels = mglevels[0]->levels; 170506792cafSBarry Smith 170606792cafSBarry Smith for (i = 1; i < levels; i++) { 17079566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n)); 17089566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n)); 170906792cafSBarry Smith mg->default_smoothu = n; 171006792cafSBarry Smith mg->default_smoothd = n; 171106792cafSBarry Smith } 171206792cafSBarry Smith PetscFunctionReturn(0); 171306792cafSBarry Smith } 171406792cafSBarry Smith 1715f442ab6aSBarry Smith /*@ 17168e5aa403SBarry Smith PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate KSP from the down (pre) smoother on all levels 1717710315b6SLawrence Mitchell and adds the suffix _up to the options name 1718f442ab6aSBarry Smith 1719f442ab6aSBarry Smith Logically Collective on PC 1720f442ab6aSBarry Smith 1721f442ab6aSBarry Smith Input Parameters: 1722f442ab6aSBarry Smith . pc - the preconditioner context 1723f442ab6aSBarry Smith 1724f442ab6aSBarry Smith Options Database Key: 1725147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1726f442ab6aSBarry Smith 1727f442ab6aSBarry Smith Level: advanced 1728f442ab6aSBarry Smith 172995452b02SPatrick Sanan Notes: 173095452b02SPatrick Sanan this does not set a value on the coarsest grid, since we assume that 1731f442ab6aSBarry Smith there is no separate smooth up on the coarsest grid. 1732f442ab6aSBarry Smith 1733db781477SPatrick Sanan .seealso: `PCMGSetNumberSmooth()` 1734f442ab6aSBarry Smith @*/ 17359371c9d4SSatish Balay PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) { 1736f442ab6aSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1737f442ab6aSBarry Smith PC_MG_Levels **mglevels = mg->levels; 1738f442ab6aSBarry Smith PetscInt i, levels; 1739f442ab6aSBarry Smith KSP subksp; 1740f442ab6aSBarry Smith 1741f442ab6aSBarry Smith PetscFunctionBegin; 1742f442ab6aSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 174328b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1744f442ab6aSBarry Smith levels = mglevels[0]->levels; 1745f442ab6aSBarry Smith 1746f442ab6aSBarry Smith for (i = 1; i < levels; i++) { 1747710315b6SLawrence Mitchell const char *prefix = NULL; 1748f442ab6aSBarry Smith /* make sure smoother up and down are different */ 17499566063dSJacob Faibussowitsch PetscCall(PCMGGetSmootherUp(pc, i, &subksp)); 17509566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix)); 17519566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(subksp, prefix)); 17529566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(subksp, "up_")); 1753f442ab6aSBarry Smith } 1754f442ab6aSBarry Smith PetscFunctionReturn(0); 1755f442ab6aSBarry Smith } 1756f442ab6aSBarry Smith 175707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 17589371c9d4SSatish Balay PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) { 175907a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 176007a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 176107a4832bSFande Kong Mat *mat; 176207a4832bSFande Kong PetscInt l; 176307a4832bSFande Kong 176407a4832bSFande Kong PetscFunctionBegin; 176528b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 17669566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 176707a4832bSFande Kong for (l = 1; l < mg->nlevels; l++) { 176807a4832bSFande Kong mat[l - 1] = mglevels[l]->interpolate; 17699566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l - 1])); 177007a4832bSFande Kong } 177107a4832bSFande Kong *num_levels = mg->nlevels; 177207a4832bSFande Kong *interpolations = mat; 177307a4832bSFande Kong PetscFunctionReturn(0); 177407a4832bSFande Kong } 177507a4832bSFande Kong 177607a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 17779371c9d4SSatish Balay PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) { 177807a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 177907a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 178007a4832bSFande Kong PetscInt l; 178107a4832bSFande Kong Mat *mat; 178207a4832bSFande Kong 178307a4832bSFande Kong PetscFunctionBegin; 178428b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 17859566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 178607a4832bSFande Kong for (l = 0; l < mg->nlevels - 1; l++) { 17879566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &(mat[l]))); 17889566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l])); 178907a4832bSFande Kong } 179007a4832bSFande Kong *num_levels = mg->nlevels; 179107a4832bSFande Kong *coarseOperators = mat; 179207a4832bSFande Kong PetscFunctionReturn(0); 179307a4832bSFande Kong } 179407a4832bSFande Kong 1795f3b08a26SMatthew G. Knepley /*@C 1796f3b08a26SMatthew G. Knepley PCMGRegisterCoarseSpaceConstructor - Adds a method to the PCMG package for coarse space construction. 1797f3b08a26SMatthew G. Knepley 1798f3b08a26SMatthew G. Knepley Not collective 1799f3b08a26SMatthew G. Knepley 1800f3b08a26SMatthew G. Knepley Input Parameters: 1801f3b08a26SMatthew G. Knepley + name - name of the constructor 1802f3b08a26SMatthew G. Knepley - function - constructor routine 1803f3b08a26SMatthew G. Knepley 1804f3b08a26SMatthew G. Knepley Notes: 1805f3b08a26SMatthew G. Knepley Calling sequence for the routine: 18062b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp) 1807f3b08a26SMatthew G. Knepley $ pc - The PC object 1808f3b08a26SMatthew G. Knepley $ l - The multigrid level, 0 is the coarse level 1809f3b08a26SMatthew G. Knepley $ dm - The DM for this level 1810f3b08a26SMatthew G. Knepley $ smooth - The level smoother 1811f3b08a26SMatthew G. Knepley $ Nc - The size of the coarse space 1812f3b08a26SMatthew G. Knepley $ initGuess - Basis for an initial guess for the space 1813f3b08a26SMatthew G. Knepley $ coarseSp - A basis for the computed coarse space 1814f3b08a26SMatthew G. Knepley 1815f3b08a26SMatthew G. Knepley Level: advanced 1816f3b08a26SMatthew G. Knepley 1817db781477SPatrick Sanan .seealso: `PCMGGetCoarseSpaceConstructor()`, `PCRegister()` 1818f3b08a26SMatthew G. Knepley @*/ 18199371c9d4SSatish Balay PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) { 1820f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18219566063dSJacob Faibussowitsch PetscCall(PCInitializePackage()); 18229566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function)); 1823f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1824f3b08a26SMatthew G. Knepley } 1825f3b08a26SMatthew G. Knepley 1826f3b08a26SMatthew G. Knepley /*@C 1827f3b08a26SMatthew G. Knepley PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1828f3b08a26SMatthew G. Knepley 1829f3b08a26SMatthew G. Knepley Not collective 1830f3b08a26SMatthew G. Knepley 1831f3b08a26SMatthew G. Knepley Input Parameter: 1832f3b08a26SMatthew G. Knepley . name - name of the constructor 1833f3b08a26SMatthew G. Knepley 1834f3b08a26SMatthew G. Knepley Output Parameter: 1835f3b08a26SMatthew G. Knepley . function - constructor routine 1836f3b08a26SMatthew G. Knepley 1837f3b08a26SMatthew G. Knepley Notes: 1838f3b08a26SMatthew G. Knepley Calling sequence for the routine: 18392b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp) 1840f3b08a26SMatthew G. Knepley $ pc - The PC object 1841f3b08a26SMatthew G. Knepley $ l - The multigrid level, 0 is the coarse level 1842f3b08a26SMatthew G. Knepley $ dm - The DM for this level 1843f3b08a26SMatthew G. Knepley $ smooth - The level smoother 1844f3b08a26SMatthew G. Knepley $ Nc - The size of the coarse space 1845f3b08a26SMatthew G. Knepley $ initGuess - Basis for an initial guess for the space 1846f3b08a26SMatthew G. Knepley $ coarseSp - A basis for the computed coarse space 1847f3b08a26SMatthew G. Knepley 1848f3b08a26SMatthew G. Knepley Level: advanced 1849f3b08a26SMatthew G. Knepley 1850db781477SPatrick Sanan .seealso: `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()` 1851f3b08a26SMatthew G. Knepley @*/ 18529371c9d4SSatish Balay PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) { 1853f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18549566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function)); 1855f3b08a26SMatthew G. Knepley PetscFunctionReturn(0); 1856f3b08a26SMatthew G. Knepley } 1857f3b08a26SMatthew G. Knepley 18584b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/ 18594b9ad928SBarry Smith 18603b09bd56SBarry Smith /*MC 1861ccb205f8SBarry Smith PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 18623b09bd56SBarry Smith information about the coarser grid matrices and restriction/interpolation operators. 18633b09bd56SBarry Smith 18643b09bd56SBarry Smith Options Database Keys: 18653b09bd56SBarry Smith + -pc_mg_levels <nlevels> - number of levels including finest 1866391689abSStefano Zampini . -pc_mg_cycle_type <v,w> - provide the cycle desired 18678c1c2452SJed Brown . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 18683b09bd56SBarry Smith . -pc_mg_log - log information about time spent on each level of the solver 1869710315b6SLawrence Mitchell . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 18702134b1e4SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 18718cf6037eSBarry Smith . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 18728cf6037eSBarry Smith . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1873e3c5b3baSBarry Smith to the Socket viewer for reading from MATLAB. 18748cf6037eSBarry Smith - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 18758cf6037eSBarry Smith to the binary output file called binaryoutput 18763b09bd56SBarry Smith 187795452b02SPatrick Sanan Notes: 18780b3c753eSRichard Tran Mills If one uses a Krylov method such GMRES or CG as the smoother then one must use KSPFGMRES, KSPGCR, or KSPRICHARDSON as the outer Krylov method 18793b09bd56SBarry Smith 18808cf6037eSBarry Smith When run with a single level the smoother options are used on that level NOT the coarse grid solver options 18818cf6037eSBarry Smith 188223067569SBarry Smith When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 188323067569SBarry Smith is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 188423067569SBarry Smith (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 188523067569SBarry Smith residual is computed at the end of each cycle. 188623067569SBarry Smith 18873b09bd56SBarry Smith Level: intermediate 18883b09bd56SBarry Smith 1889db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE` 1890db781477SPatrick Sanan `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`, 1891db781477SPatrick Sanan `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`, 1892db781477SPatrick Sanan `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, 1893db781477SPatrick Sanan `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()` 18943b09bd56SBarry Smith M*/ 18953b09bd56SBarry Smith 18969371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) { 1897f3fbd535SBarry Smith PC_MG *mg; 1898f3fbd535SBarry Smith 18994b9ad928SBarry Smith PetscFunctionBegin; 19009566063dSJacob Faibussowitsch PetscCall(PetscNewLog(pc, &mg)); 19013ec1f749SStefano Zampini pc->data = mg; 1902f3fbd535SBarry Smith mg->nlevels = -1; 190310eca3edSLisandro Dalcin mg->am = PC_MG_MULTIPLICATIVE; 19042134b1e4SBarry Smith mg->galerkin = PC_MG_GALERKIN_NONE; 1905f3b08a26SMatthew G. Knepley mg->adaptInterpolation = PETSC_FALSE; 1906f3b08a26SMatthew G. Knepley mg->Nc = -1; 1907f3b08a26SMatthew G. Knepley mg->eigenvalue = -1; 1908f3fbd535SBarry Smith 190937a44384SMark Adams pc->useAmat = PETSC_TRUE; 191037a44384SMark Adams 19114b9ad928SBarry Smith pc->ops->apply = PCApply_MG; 1912fcb023d4SJed Brown pc->ops->applytranspose = PCApplyTranspose_MG; 191330b0564aSStefano Zampini pc->ops->matapply = PCMatApply_MG; 19144b9ad928SBarry Smith pc->ops->setup = PCSetUp_MG; 1915a06653b4SBarry Smith pc->ops->reset = PCReset_MG; 19164b9ad928SBarry Smith pc->ops->destroy = PCDestroy_MG; 19174b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_MG; 19184b9ad928SBarry Smith pc->ops->view = PCView_MG; 1919fb15c04eSBarry Smith 19209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue)); 19219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG)); 19229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG)); 19239566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG)); 19249566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG)); 19259566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG)); 19269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG)); 19279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG)); 19289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG)); 19299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG)); 19302b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG)); 19312b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG)); 19324b9ad928SBarry Smith PetscFunctionReturn(0); 19334b9ad928SBarry Smith } 1934