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 15d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) 16d71ae5a4SJacob Faibussowitsch { 1731567311SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1831567311SBarry Smith PC_MG_Levels *mgc, *mglevels = *mglevelsin; 1931567311SBarry Smith PetscInt cycles = (mglevels->level == 1) ? 1 : (PetscInt)mglevels->cycles; 204b9ad928SBarry Smith 214b9ad928SBarry Smith PetscFunctionBegin; 229566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 23fcb023d4SJed Brown if (!transpose) { 2430b0564aSStefano Zampini if (matapp) { 259566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */ 269566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL)); 2730b0564aSStefano Zampini } else { 289566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */ 299566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 3030b0564aSStefano Zampini } 31fcb023d4SJed Brown } else { 3228b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 339566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */ 349566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 35fcb023d4SJed Brown } 369566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 3731567311SBarry Smith if (mglevels->level) { /* not the coarsest grid */ 389566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0)); 3948a46eb9SPierre Jolivet if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R)); 40fcb023d4SJed Brown if (!transpose) { 419566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 429566063dSJacob Faibussowitsch else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 43fcb023d4SJed Brown } else { 449566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 459566063dSJacob Faibussowitsch else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 46fcb023d4SJed Brown } 479566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0)); 484b9ad928SBarry Smith 494b9ad928SBarry Smith /* if on finest level and have convergence criteria set */ 5031567311SBarry Smith if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) { 514b9ad928SBarry Smith PetscReal rnorm; 529566063dSJacob Faibussowitsch PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm)); 534b9ad928SBarry Smith if (rnorm <= mg->ttol) { 5470441072SBarry Smith if (rnorm < mg->abstol) { 554d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_ATOL; 569566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol)); 574b9ad928SBarry Smith } else { 584d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_RTOL; 599566063dSJacob 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)); 604b9ad928SBarry Smith } 613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 624b9ad928SBarry Smith } 634b9ad928SBarry Smith } 644b9ad928SBarry Smith 6531567311SBarry Smith mgc = *(mglevelsin - 1); 669566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 67fcb023d4SJed Brown if (!transpose) { 689566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B)); 699566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b)); 70fcb023d4SJed Brown } else { 719566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B)); 729566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b)); 73fcb023d4SJed Brown } 749566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 7530b0564aSStefano Zampini if (matapp) { 7630b0564aSStefano Zampini if (!mgc->X) { 779566063dSJacob Faibussowitsch PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X)); 7830b0564aSStefano Zampini } else { 799566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mgc->X)); 8030b0564aSStefano Zampini } 8130b0564aSStefano Zampini } else { 829566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mgc->x)); 8330b0564aSStefano Zampini } 8448a46eb9SPierre Jolivet while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason)); 859566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 86fcb023d4SJed Brown if (!transpose) { 879566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X)); 889566063dSJacob Faibussowitsch else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x)); 89fcb023d4SJed Brown } else { 909566063dSJacob Faibussowitsch PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x)); 91fcb023d4SJed Brown } 929566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 939566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 94fcb023d4SJed Brown if (!transpose) { 9530b0564aSStefano Zampini if (matapp) { 969566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */ 979566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL)); 9830b0564aSStefano Zampini } else { 999566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */ 1009566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 10130b0564aSStefano Zampini } 102fcb023d4SJed Brown } else { 10328b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 1049566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */ 1059566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 106fcb023d4SJed Brown } 10741b6fd38SMatthew G. Knepley if (mglevels->cr) { 10828b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 10941b6fd38SMatthew G. Knepley /* TODO Turn on copy and turn off noisy if we have an exact solution 1109566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->x, mglevels->crx)); 1119566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->b, mglevels->crb)); */ 1129566063dSJacob Faibussowitsch PetscCall(KSPSetNoisy_Private(mglevels->crx)); 1139566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */ 1149566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx)); 11541b6fd38SMatthew G. Knepley } 1169566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 1174b9ad928SBarry Smith } 1183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1194b9ad928SBarry Smith } 1204b9ad928SBarry Smith 121d71ae5a4SJacob Faibussowitsch 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) 122d71ae5a4SJacob Faibussowitsch { 123f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 124f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 125391689abSStefano Zampini PC tpc; 126391689abSStefano Zampini PetscBool changeu, changed; 127f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 1284b9ad928SBarry Smith 1294b9ad928SBarry Smith PetscFunctionBegin; 130a762d673SBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 131a762d673SBarry Smith for (i = 0; i < levels; i++) { 132a762d673SBarry Smith if (!mglevels[i]->A) { 1339566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 1349566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 135a762d673SBarry Smith } 136a762d673SBarry Smith } 137391689abSStefano Zampini 1389566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 1399566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 1409566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 1419566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 142391689abSStefano Zampini if (!changed && !changeu) { 1439566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 144f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 145391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 146391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 147391689abSStefano Zampini Vec *vec; 148391689abSStefano Zampini 1499566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 150391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 1519566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 152391689abSStefano Zampini } 1539566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 154391689abSStefano Zampini } 155f3fbd535SBarry Smith mglevels[levels - 1]->x = x; 1564b9ad928SBarry Smith 15731567311SBarry Smith mg->rtol = rtol; 15831567311SBarry Smith mg->abstol = abstol; 15931567311SBarry Smith mg->dtol = dtol; 1604b9ad928SBarry Smith if (rtol) { 1614b9ad928SBarry Smith /* compute initial residual norm for relative convergence test */ 1624b9ad928SBarry Smith PetscReal rnorm; 1637319c654SBarry Smith if (zeroguess) { 1649566063dSJacob Faibussowitsch PetscCall(VecNorm(b, NORM_2, &rnorm)); 1657319c654SBarry Smith } else { 1669566063dSJacob Faibussowitsch PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w)); 1679566063dSJacob Faibussowitsch PetscCall(VecNorm(w, NORM_2, &rnorm)); 1687319c654SBarry Smith } 16931567311SBarry Smith mg->ttol = PetscMax(rtol * rnorm, abstol); 1702fa5cd67SKarl Rupp } else if (abstol) mg->ttol = abstol; 1712fa5cd67SKarl Rupp else mg->ttol = 0.0; 1724b9ad928SBarry Smith 1734d0a8057SBarry Smith /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 174336babb1SJed Brown stop prematurely due to small residual */ 1754d0a8057SBarry Smith for (i = 1; i < levels; i++) { 1769566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); 177f3fbd535SBarry Smith if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 17823067569SBarry Smith /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */ 1799566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1809566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); 1814b9ad928SBarry Smith } 1824d0a8057SBarry Smith } 1834d0a8057SBarry Smith 1844d0a8057SBarry Smith *reason = (PCRichardsonConvergedReason)0; 1854d0a8057SBarry Smith for (i = 0; i < its; i++) { 1869566063dSJacob Faibussowitsch PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason)); 1874d0a8057SBarry Smith if (*reason) break; 1884d0a8057SBarry Smith } 1894d0a8057SBarry Smith if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 1904d0a8057SBarry Smith *outits = i; 191391689abSStefano Zampini if (!changed && !changeu) mglevels[levels - 1]->b = NULL; 1923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1934b9ad928SBarry Smith } 1944b9ad928SBarry Smith 195d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc) 196d71ae5a4SJacob Faibussowitsch { 1973aeaf226SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1983aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 1992b3cbbdaSStefano Zampini PetscInt i, n; 2003aeaf226SBarry Smith 2013aeaf226SBarry Smith PetscFunctionBegin; 2023aeaf226SBarry Smith if (mglevels) { 2033aeaf226SBarry Smith n = mglevels[0]->levels; 2043aeaf226SBarry Smith for (i = 0; i < n - 1; i++) { 2059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->r)); 2069566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->b)); 2079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->x)); 2089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->R)); 2099566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 2109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 2119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crx)); 2129566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crb)); 2139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->restrct)); 2149566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->interpolate)); 2159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->inject)); 2169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->rscale)); 2173aeaf226SBarry Smith } 2189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crx)); 2199566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crb)); 220391689abSStefano Zampini /* this is not null only if the smoother on the finest level 221391689abSStefano Zampini changes the rhs during PreSolve */ 2229566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->b)); 2239566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[n - 1]->B)); 2243aeaf226SBarry Smith 2253aeaf226SBarry Smith for (i = 0; i < n; i++) { 2262b3cbbdaSStefano Zampini PetscCall(MatDestroy(&mglevels[i]->coarseSpace)); 2279566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->A)); 22848a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd)); 2299566063dSJacob Faibussowitsch PetscCall(KSPReset(mglevels[i]->smoothu)); 2309566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr)); 2313aeaf226SBarry Smith } 232f3b08a26SMatthew G. Knepley mg->Nc = 0; 2333aeaf226SBarry Smith } 2343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2353aeaf226SBarry Smith } 2363aeaf226SBarry Smith 23741b6fd38SMatthew G. Knepley /* Implementing CR 23841b6fd38SMatthew G. Knepley 23941b6fd38SMatthew 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 24041b6fd38SMatthew G. Knepley 24141b6fd38SMatthew G. Knepley Inj^T (Inj Inj^T)^{-1} Inj 24241b6fd38SMatthew G. Knepley 24341b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have 24441b6fd38SMatthew G. Knepley 24541b6fd38SMatthew G. Knepley Inj^T Inj 24641b6fd38SMatthew G. Knepley 24741b6fd38SMatthew G. Knepley and 24841b6fd38SMatthew G. Knepley 24941b6fd38SMatthew G. Knepley S = I - Inj^T Inj 25041b6fd38SMatthew G. Knepley 25141b6fd38SMatthew G. Knepley since 25241b6fd38SMatthew G. Knepley 25341b6fd38SMatthew G. Knepley Inj S = Inj - (Inj Inj^T) Inj = 0. 25441b6fd38SMatthew G. Knepley 25541b6fd38SMatthew G. Knepley Brannick suggests 25641b6fd38SMatthew G. Knepley 25741b6fd38SMatthew G. Knepley A \to S^T A S \qquad\mathrm{and}\qquad M \to S^T M S 25841b6fd38SMatthew G. Knepley 25941b6fd38SMatthew 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 26041b6fd38SMatthew G. Knepley 26141b6fd38SMatthew G. Knepley M^{-1} A \to S M^{-1} A S 26241b6fd38SMatthew G. Knepley 26341b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left. 26441b6fd38SMatthew G. Knepley 26541b6fd38SMatthew G. Knepley Check: || Inj P - I ||_F < tol 26641b6fd38SMatthew G. Knepley Check: In general, Inj Inj^T = I 26741b6fd38SMatthew G. Knepley */ 26841b6fd38SMatthew G. Knepley 26941b6fd38SMatthew G. Knepley typedef struct { 27041b6fd38SMatthew G. Knepley PC mg; /* The PCMG object */ 27141b6fd38SMatthew G. Knepley PetscInt l; /* The multigrid level for this solver */ 27241b6fd38SMatthew G. Knepley Mat Inj; /* The injection matrix */ 27341b6fd38SMatthew G. Knepley Mat S; /* I - Inj^T Inj */ 27441b6fd38SMatthew G. Knepley } CRContext; 27541b6fd38SMatthew G. Knepley 276d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc) 277d71ae5a4SJacob Faibussowitsch { 27841b6fd38SMatthew G. Knepley CRContext *ctx; 27941b6fd38SMatthew G. Knepley Mat It; 28041b6fd38SMatthew G. Knepley 28141b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2829566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 2839566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It)); 28428b400f6SJacob Faibussowitsch PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG"); 2859566063dSJacob Faibussowitsch PetscCall(MatCreateTranspose(It, &ctx->Inj)); 2869566063dSJacob Faibussowitsch PetscCall(MatCreateNormal(ctx->Inj, &ctx->S)); 2879566063dSJacob Faibussowitsch PetscCall(MatScale(ctx->S, -1.0)); 2889566063dSJacob Faibussowitsch PetscCall(MatShift(ctx->S, 1.0)); 2893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 29041b6fd38SMatthew G. Knepley } 29141b6fd38SMatthew G. Knepley 292d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y) 293d71ae5a4SJacob Faibussowitsch { 29441b6fd38SMatthew G. Knepley CRContext *ctx; 29541b6fd38SMatthew G. Knepley 29641b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2979566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 2989566063dSJacob Faibussowitsch PetscCall(MatMult(ctx->S, x, y)); 2993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30041b6fd38SMatthew G. Knepley } 30141b6fd38SMatthew G. Knepley 302d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc) 303d71ae5a4SJacob Faibussowitsch { 30441b6fd38SMatthew G. Knepley CRContext *ctx; 30541b6fd38SMatthew G. Knepley 30641b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3079566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 3089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->Inj)); 3099566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->S)); 3109566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 3119566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(pc, NULL)); 3123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 31341b6fd38SMatthew G. Knepley } 31441b6fd38SMatthew G. Knepley 315d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr) 316d71ae5a4SJacob Faibussowitsch { 31741b6fd38SMatthew G. Knepley CRContext *ctx; 31841b6fd38SMatthew G. Knepley 31941b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3209566063dSJacob Faibussowitsch PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr)); 3219566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)")); 3229566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(1, &ctx)); 32341b6fd38SMatthew G. Knepley ctx->mg = pc; 32441b6fd38SMatthew G. Knepley ctx->l = l; 3259566063dSJacob Faibussowitsch PetscCall(PCSetType(*cr, PCSHELL)); 3269566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(*cr, ctx)); 3279566063dSJacob Faibussowitsch PetscCall(PCShellSetApply(*cr, CRApply_Private)); 3289566063dSJacob Faibussowitsch PetscCall(PCShellSetSetUp(*cr, CRSetup_Private)); 3299566063dSJacob Faibussowitsch PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private)); 3303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33141b6fd38SMatthew G. Knepley } 33241b6fd38SMatthew G. Knepley 333d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms) 334d71ae5a4SJacob Faibussowitsch { 335f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 336ce94432eSBarry Smith MPI_Comm comm; 3373aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 33810eca3edSLisandro Dalcin PCMGType mgtype = mg->am; 33910167fecSBarry Smith PetscInt mgctype = (PetscInt)PC_MG_CYCLE_V; 340f3fbd535SBarry Smith PetscInt i; 341f3fbd535SBarry Smith PetscMPIInt size; 342f3fbd535SBarry Smith const char *prefix; 343f3fbd535SBarry Smith PC ipc; 3443aeaf226SBarry Smith PetscInt n; 3454b9ad928SBarry Smith 3464b9ad928SBarry Smith PetscFunctionBegin; 3470700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 348548767e0SJed Brown PetscValidLogicalCollectiveInt(pc, levels, 2); 3493ba16761SJacob Faibussowitsch if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS); 3509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 3513aeaf226SBarry Smith if (mglevels) { 35210eca3edSLisandro Dalcin mgctype = mglevels[0]->cycles; 3533aeaf226SBarry Smith /* changing the number of levels so free up the previous stuff */ 3549566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 3553aeaf226SBarry Smith n = mglevels[0]->levels; 3563aeaf226SBarry Smith for (i = 0; i < n; i++) { 35748a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 3589566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 3599566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 3609566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 3613aeaf226SBarry Smith } 3629566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 3633aeaf226SBarry Smith } 364f3fbd535SBarry Smith 365f3fbd535SBarry Smith mg->nlevels = levels; 366f3fbd535SBarry Smith 3679566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(levels, &mglevels)); 368f3fbd535SBarry Smith 3699566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 370f3fbd535SBarry Smith 371a9db87a2SMatthew G Knepley mg->stageApply = 0; 372f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 3734dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mglevels[i])); 3742fa5cd67SKarl Rupp 375f3fbd535SBarry Smith mglevels[i]->level = i; 376f3fbd535SBarry Smith mglevels[i]->levels = levels; 37710eca3edSLisandro Dalcin mglevels[i]->cycles = mgctype; 378336babb1SJed Brown mg->default_smoothu = 2; 379336babb1SJed Brown mg->default_smoothd = 2; 38063e6d426SJed Brown mglevels[i]->eventsmoothsetup = 0; 38163e6d426SJed Brown mglevels[i]->eventsmoothsolve = 0; 38263e6d426SJed Brown mglevels[i]->eventresidual = 0; 38363e6d426SJed Brown mglevels[i]->eventinterprestrict = 0; 384f3fbd535SBarry Smith 385f3fbd535SBarry Smith if (comms) comm = comms[i]; 386d5a8f7e6SBarry Smith if (comm != MPI_COMM_NULL) { 3879566063dSJacob Faibussowitsch PetscCall(KSPCreate(comm, &mglevels[i]->smoothd)); 3883821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel)); 3899566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure)); 3909566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i)); 3919566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix)); 3929566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level)); 3930ee9a668SBarry Smith if (i || levels == 1) { 3940ee9a668SBarry Smith char tprefix[128]; 3950ee9a668SBarry Smith 3969566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV)); 3979566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL)); 3989566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE)); 3999566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc)); 4009566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCSOR)); 4019566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd)); 402f3fbd535SBarry Smith 4039566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%d_", (int)i)); 4049566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 4050ee9a668SBarry Smith } else { 4069566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_")); 407f3fbd535SBarry Smith 4089dbfc187SHong Zhang /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 4099566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY)); 4109566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc)); 4119566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 412f3fbd535SBarry Smith if (size > 1) { 4139566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCREDUNDANT)); 414f3fbd535SBarry Smith } else { 4159566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCLU)); 416f3fbd535SBarry Smith } 4179566063dSJacob Faibussowitsch PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS)); 418f3fbd535SBarry Smith } 419d5a8f7e6SBarry Smith } 420f3fbd535SBarry Smith mglevels[i]->smoothu = mglevels[i]->smoothd; 42131567311SBarry Smith mg->rtol = 0.0; 42231567311SBarry Smith mg->abstol = 0.0; 42331567311SBarry Smith mg->dtol = 0.0; 42431567311SBarry Smith mg->ttol = 0.0; 42531567311SBarry Smith mg->cyclesperpcapply = 1; 426f3fbd535SBarry Smith } 427f3fbd535SBarry Smith mg->levels = mglevels; 4289566063dSJacob Faibussowitsch PetscCall(PCMGSetType(pc, mgtype)); 4293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4304b9ad928SBarry Smith } 4314b9ad928SBarry Smith 43297d33e41SMatthew G. Knepley /*@C 433f1580f4eSBarry Smith PCMGSetLevels - Sets the number of levels to use with `PCMG`. 434f1580f4eSBarry Smith Must be called before any other `PCMG` routine. 43597d33e41SMatthew G. Knepley 436c3339decSBarry Smith Logically Collective 43797d33e41SMatthew G. Knepley 43897d33e41SMatthew G. Knepley Input Parameters: 43997d33e41SMatthew G. Knepley + pc - the preconditioner context 44097d33e41SMatthew G. Knepley . levels - the number of levels 44197d33e41SMatthew G. Knepley - comms - optional communicators for each level; this is to allow solving the coarser problems 442d5a8f7e6SBarry Smith on smaller sets of processes. For processes that are not included in the computation 44320f4b53cSBarry Smith you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes 44405552d4bSJunchao Zhang should participate in each level of problem. 44597d33e41SMatthew G. Knepley 44697d33e41SMatthew G. Knepley Level: intermediate 44797d33e41SMatthew G. Knepley 44897d33e41SMatthew G. Knepley Notes: 44920f4b53cSBarry Smith If the number of levels is one then the multigrid uses the `-mg_levels` prefix 45020f4b53cSBarry Smith for setting the level options rather than the `-mg_coarse` prefix. 45197d33e41SMatthew G. Knepley 452d5a8f7e6SBarry Smith You can free the information in comms after this routine is called. 453d5a8f7e6SBarry Smith 454f1580f4eSBarry Smith The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level 455d5a8f7e6SBarry Smith are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on 456d5a8f7e6SBarry Smith the two levels, rank 0 in the original communicator will pass in an array of 2 communicators 457d5a8f7e6SBarry Smith of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators 458f1580f4eSBarry Smith the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate 459d5a8f7e6SBarry Smith in the coarse grid solve. 460d5a8f7e6SBarry Smith 461f1580f4eSBarry Smith Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one 462d5a8f7e6SBarry Smith must take special care in providing the restriction and interpolation operation. We recommend 463d5a8f7e6SBarry Smith providing these as two step operations; first perform a standard restriction or interpolation on 464d5a8f7e6SBarry Smith the full number of ranks for that level and then use an MPI call to copy the resulting vector 46505552d4bSJunchao Zhang array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both 466d5a8f7e6SBarry Smith cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and 46720f4b53cSBarry Smith receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries. 468d5a8f7e6SBarry Smith 469feefa0e1SJacob Faibussowitsch Fortran Notes: 47020f4b53cSBarry Smith Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM` 471f1580f4eSBarry Smith is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc. 472d5a8f7e6SBarry Smith 473db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()` 47497d33e41SMatthew G. Knepley @*/ 475d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) 476d71ae5a4SJacob Faibussowitsch { 47797d33e41SMatthew G. Knepley PetscFunctionBegin; 47897d33e41SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 4794f572ea9SToby Isaac if (comms) PetscAssertPointer(comms, 3); 480cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms)); 4813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48297d33e41SMatthew G. Knepley } 48397d33e41SMatthew G. Knepley 484d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc) 485d71ae5a4SJacob Faibussowitsch { 486a06653b4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 487a06653b4SBarry Smith PC_MG_Levels **mglevels = mg->levels; 488a06653b4SBarry Smith PetscInt i, n; 489c07bf074SBarry Smith 490c07bf074SBarry Smith PetscFunctionBegin; 4919566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 492a06653b4SBarry Smith if (mglevels) { 493a06653b4SBarry Smith n = mglevels[0]->levels; 494a06653b4SBarry Smith for (i = 0; i < n; i++) { 49548a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 4969566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 4979566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 4989566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 499a06653b4SBarry Smith } 5009566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 501a06653b4SBarry Smith } 5029566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 5039566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5049566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5052b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL)); 5062b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL)); 5072b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL)); 5082b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5092b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5102b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL)); 5112b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL)); 5122b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL)); 5132b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL)); 5142b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL)); 5152b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL)); 5163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 517f3fbd535SBarry Smith } 518f3fbd535SBarry Smith 519f3fbd535SBarry Smith /* 520f3fbd535SBarry Smith PCApply_MG - Runs either an additive, multiplicative, Kaskadic 521f3fbd535SBarry Smith or full cycle of multigrid. 522f3fbd535SBarry Smith 523f3fbd535SBarry Smith Note: 524f3fbd535SBarry Smith A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 525f3fbd535SBarry Smith */ 526d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) 527d71ae5a4SJacob Faibussowitsch { 528f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 529f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 530391689abSStefano Zampini PC tpc; 531f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 53230b0564aSStefano Zampini PetscBool changeu, changed, matapp; 533f3fbd535SBarry Smith 534f3fbd535SBarry Smith PetscFunctionBegin; 53530b0564aSStefano Zampini matapp = (PetscBool)(B && X); 5369566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply)); 537e1d8e5deSBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 538298cc208SBarry Smith for (i = 0; i < levels; i++) { 539e1d8e5deSBarry Smith if (!mglevels[i]->A) { 5409566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 5419566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 542e1d8e5deSBarry Smith } 543e1d8e5deSBarry Smith } 544e1d8e5deSBarry Smith 5459566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 5469566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 5479566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 5489566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 549391689abSStefano Zampini if (!changeu && !changed) { 55030b0564aSStefano Zampini if (matapp) { 5519566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 55230b0564aSStefano Zampini mglevels[levels - 1]->B = B; 55330b0564aSStefano Zampini } else { 5549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 555f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 55630b0564aSStefano Zampini } 557391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 55830b0564aSStefano Zampini if (matapp) { 55930b0564aSStefano Zampini if (mglevels[levels - 1]->B) { 56030b0564aSStefano Zampini PetscInt N1, N2; 56130b0564aSStefano Zampini PetscBool flg; 56230b0564aSStefano Zampini 5639566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1)); 5649566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N2)); 5659566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg)); 56648a46eb9SPierre Jolivet if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 56730b0564aSStefano Zampini } 56830b0564aSStefano Zampini if (!mglevels[levels - 1]->B) { 5699566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B)); 57030b0564aSStefano Zampini } else { 5719566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN)); 57230b0564aSStefano Zampini } 57330b0564aSStefano Zampini } else { 574391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 575391689abSStefano Zampini Vec *vec; 576391689abSStefano Zampini 5779566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 578391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 5799566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 580391689abSStefano Zampini } 5819566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 582391689abSStefano Zampini } 58330b0564aSStefano Zampini } 5849371c9d4SSatish Balay if (matapp) { 5859371c9d4SSatish Balay mglevels[levels - 1]->X = X; 5869371c9d4SSatish Balay } else { 5879371c9d4SSatish Balay mglevels[levels - 1]->x = x; 5889371c9d4SSatish Balay } 58930b0564aSStefano Zampini 59030b0564aSStefano Zampini /* If coarser Xs are present, it means we have already block applied the PC at least once 59130b0564aSStefano Zampini Reset operators if sizes/type do no match */ 59230b0564aSStefano Zampini if (matapp && levels > 1 && mglevels[levels - 2]->X) { 59330b0564aSStefano Zampini PetscInt Xc, Bc; 59430b0564aSStefano Zampini PetscBool flg; 59530b0564aSStefano Zampini 5969566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc)); 5979566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc)); 5989566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg)); 59930b0564aSStefano Zampini if (Xc != Bc || !flg) { 6009566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->R)); 60130b0564aSStefano Zampini for (i = 0; i < levels - 1; i++) { 6029566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->R)); 6039566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 6049566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 60530b0564aSStefano Zampini } 60630b0564aSStefano Zampini } 60730b0564aSStefano Zampini } 608391689abSStefano Zampini 60931567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6109566063dSJacob Faibussowitsch if (matapp) PetscCall(MatZeroEntries(X)); 6119566063dSJacob Faibussowitsch else PetscCall(VecZeroEntries(x)); 61248a46eb9SPierre Jolivet for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL)); 6132fa5cd67SKarl Rupp } else if (mg->am == PC_MG_ADDITIVE) { 6149566063dSJacob Faibussowitsch PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp)); 6152fa5cd67SKarl Rupp } else if (mg->am == PC_MG_KASKADE) { 6169566063dSJacob Faibussowitsch PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp)); 6172fa5cd67SKarl Rupp } else { 6189566063dSJacob Faibussowitsch PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp)); 619f3fbd535SBarry Smith } 6209566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePop()); 62130b0564aSStefano Zampini if (!changeu && !changed) { 6229371c9d4SSatish Balay if (matapp) { 6239371c9d4SSatish Balay mglevels[levels - 1]->B = NULL; 6249371c9d4SSatish Balay } else { 6259371c9d4SSatish Balay mglevels[levels - 1]->b = NULL; 6269371c9d4SSatish Balay } 62730b0564aSStefano Zampini } 6283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 629f3fbd535SBarry Smith } 630f3fbd535SBarry Smith 631d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) 632d71ae5a4SJacob Faibussowitsch { 633fcb023d4SJed Brown PetscFunctionBegin; 6349566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE)); 6353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 636fcb023d4SJed Brown } 637fcb023d4SJed Brown 638d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) 639d71ae5a4SJacob Faibussowitsch { 640fcb023d4SJed Brown PetscFunctionBegin; 6419566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE)); 6423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 64330b0564aSStefano Zampini } 64430b0564aSStefano Zampini 645d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) 646d71ae5a4SJacob Faibussowitsch { 64730b0564aSStefano Zampini PetscFunctionBegin; 6489566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE)); 6493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 650fcb023d4SJed Brown } 651f3fbd535SBarry Smith 652d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject) 653d71ae5a4SJacob Faibussowitsch { 654710315b6SLawrence Mitchell PetscInt levels, cycles; 655f3b08a26SMatthew G. Knepley PetscBool flg, flg2; 656f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 6573d3eaba7SBarry Smith PC_MG_Levels **mglevels; 658f3fbd535SBarry Smith PCMGType mgtype; 659f3fbd535SBarry Smith PCMGCycleType mgctype; 6602134b1e4SBarry Smith PCMGGalerkinType gtype; 6612b3cbbdaSStefano Zampini PCMGCoarseSpaceType coarseSpaceType; 662f3fbd535SBarry Smith 663f3fbd535SBarry Smith PetscFunctionBegin; 6641d743356SStefano Zampini levels = PetscMax(mg->nlevels, 1); 665d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options"); 6669566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg)); 6671a97d7b6SStefano Zampini if (!flg && !mg->levels && pc->dm) { 6689566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 669eb3f98d2SBarry Smith levels++; 6703aeaf226SBarry Smith mg->usedmfornumberoflevels = PETSC_TRUE; 671eb3f98d2SBarry Smith } 6729566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 6733aeaf226SBarry Smith mglevels = mg->levels; 6743aeaf226SBarry Smith 675f3fbd535SBarry Smith mgctype = (PCMGCycleType)mglevels[0]->cycles; 6769566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg)); 6771baa6e33SBarry Smith if (flg) PetscCall(PCMGSetCycleType(pc, mgctype)); 6782134b1e4SBarry Smith gtype = mg->galerkin; 6799566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)gtype, (PetscEnum *)>ype, &flg)); 6801baa6e33SBarry Smith if (flg) PetscCall(PCMGSetGalerkin(pc, gtype)); 6812b3cbbdaSStefano Zampini coarseSpaceType = mg->coarseSpaceType; 6822b3cbbdaSStefano 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)); 6832b3cbbdaSStefano Zampini if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType)); 6849566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg)); 6859566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg)); 68641b6fd38SMatthew G. Knepley flg2 = PETSC_FALSE; 6879566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg)); 6889566063dSJacob Faibussowitsch if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2)); 689f56b1265SBarry Smith flg = PETSC_FALSE; 6909566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL)); 6911baa6e33SBarry Smith if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc)); 69231567311SBarry Smith mgtype = mg->am; 6939566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg)); 6941baa6e33SBarry Smith if (flg) PetscCall(PCMGSetType(pc, mgtype)); 69531567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6969566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg)); 6971baa6e33SBarry Smith if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles)); 698f3fbd535SBarry Smith } 699f3fbd535SBarry Smith flg = PETSC_FALSE; 7009566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL)); 701f3fbd535SBarry Smith if (flg) { 702f3fbd535SBarry Smith PetscInt i; 703f3fbd535SBarry Smith char eventname[128]; 7041a97d7b6SStefano Zampini 705f3fbd535SBarry Smith levels = mglevels[0]->levels; 706f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 707a364092eSJacob Faibussowitsch PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %d", (int)i)); 7089566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup)); 709a364092eSJacob Faibussowitsch PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %d", (int)i)); 7109566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve)); 711f3fbd535SBarry Smith if (i) { 712a364092eSJacob Faibussowitsch PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %d", (int)i)); 7139566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual)); 714a364092eSJacob Faibussowitsch PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %d", (int)i)); 7159566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict)); 716f3fbd535SBarry Smith } 717f3fbd535SBarry Smith } 718eec35531SMatthew G Knepley 7192611ad71SToby Isaac if (PetscDefined(USE_LOG)) { 7202611ad71SToby Isaac const char sname[] = "MG Apply"; 721eec35531SMatthew G Knepley 7222611ad71SToby Isaac PetscCall(PetscLogStageGetId(sname, &mg->stageApply)); 7232611ad71SToby Isaac if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply)); 724eec35531SMatthew G Knepley } 725f3fbd535SBarry Smith } 726d0609cedSBarry Smith PetscOptionsHeadEnd(); 727f3b08a26SMatthew G. Knepley /* Check option consistency */ 7289566063dSJacob Faibussowitsch PetscCall(PCMGGetGalerkin(pc, >ype)); 7299566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptInterpolation(pc, &flg)); 73008401ef6SPierre Jolivet PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator"); 7313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 732f3fbd535SBarry Smith } 733f3fbd535SBarry Smith 7340a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL}; 7350a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL}; 7360a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL}; 7372b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL}; 738f3fbd535SBarry Smith 7399804daf3SBarry Smith #include <petscdraw.h> 740d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) 741d71ae5a4SJacob Faibussowitsch { 742f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 743f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 744e3deeeafSJed Brown PetscInt levels = mglevels ? mglevels[0]->levels : 0, i; 745219b1045SBarry Smith PetscBool iascii, isbinary, isdraw; 746f3fbd535SBarry Smith 747f3fbd535SBarry Smith PetscFunctionBegin; 7489566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 7499566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 7509566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 751f3fbd535SBarry Smith if (iascii) { 752e3deeeafSJed Brown const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 75363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename)); 75448a46eb9SPierre Jolivet if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply)); 7552134b1e4SBarry Smith if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 7569566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n")); 7572134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 7589566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n")); 7592134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 7609566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n")); 7612134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 7629566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n")); 7634f66f45eSBarry Smith } else { 7649566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n")); 765f3fbd535SBarry Smith } 7661baa6e33SBarry Smith if (mg->view) PetscCall((*mg->view)(pc, viewer)); 767f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 76863a3b9bcSJacob Faibussowitsch if (i) { 76963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 770f3fbd535SBarry Smith } else { 77163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 772f3fbd535SBarry Smith } 7739566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7749566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 7759566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 776f3fbd535SBarry Smith if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 7779566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n")); 778f3fbd535SBarry Smith } else if (i) { 77963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 7809566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7819566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 7829566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 783f3fbd535SBarry Smith } 78441b6fd38SMatthew G. Knepley if (i && mglevels[i]->cr) { 78563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i)); 7869566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7879566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->cr, viewer)); 7889566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 78941b6fd38SMatthew G. Knepley } 790f3fbd535SBarry Smith } 7915b0b0462SBarry Smith } else if (isbinary) { 7925b0b0462SBarry Smith for (i = levels - 1; i >= 0; i--) { 7939566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 79448a46eb9SPierre Jolivet if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 7955b0b0462SBarry Smith } 796219b1045SBarry Smith } else if (isdraw) { 797219b1045SBarry Smith PetscDraw draw; 798b4375e8dSPeter Brune PetscReal x, w, y, bottom, th; 7999566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 8009566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 8019566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, NULL, &th)); 802219b1045SBarry Smith bottom = y - th; 803219b1045SBarry Smith for (i = levels - 1; i >= 0; i--) { 804b4375e8dSPeter Brune if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 8059566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 8069566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8079566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 808b4375e8dSPeter Brune } else { 809b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x); 8109566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 8119566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8129566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 8139566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 8149566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8159566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 816b4375e8dSPeter Brune } 8179566063dSJacob Faibussowitsch PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL)); 8181cd381d6SBarry Smith bottom -= th; 819219b1045SBarry Smith } 8205b0b0462SBarry Smith } 8213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 822f3fbd535SBarry Smith } 823f3fbd535SBarry Smith 824af0996ceSBarry Smith #include <petsc/private/kspimpl.h> 825cab2e9ccSBarry Smith 826f3fbd535SBarry Smith /* 827f3fbd535SBarry Smith Calls setup for the KSP on each level 828f3fbd535SBarry Smith */ 829d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc) 830d71ae5a4SJacob Faibussowitsch { 831f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 832f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 8331a97d7b6SStefano Zampini PetscInt i, n; 83498e04984SBarry Smith PC cpc; 8353db492dfSBarry Smith PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE; 836f3fbd535SBarry Smith Mat dA, dB; 837f3fbd535SBarry Smith Vec tvec; 838218a07d4SBarry Smith DM *dms; 8390a545947SLisandro Dalcin PetscViewer viewer = NULL; 84041b6fd38SMatthew G. Knepley PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE; 8412b3cbbdaSStefano Zampini PetscBool adaptInterpolation = mg->adaptInterpolation; 842f3fbd535SBarry Smith 843f3fbd535SBarry Smith PetscFunctionBegin; 84428b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up"); 8451a97d7b6SStefano Zampini n = mglevels[0]->levels; 84601bc414fSDmitry Karpeev /* FIX: Move this to PCSetFromOptions_MG? */ 8473aeaf226SBarry Smith if (mg->usedmfornumberoflevels) { 8483aeaf226SBarry Smith PetscInt levels; 8499566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 8503aeaf226SBarry Smith levels++; 8513aeaf226SBarry Smith if (levels > n) { /* the problem is now being solved on a finer grid */ 8529566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 8533aeaf226SBarry Smith n = levels; 8549566063dSJacob Faibussowitsch PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 8553aeaf226SBarry Smith mglevels = mg->levels; 8563aeaf226SBarry Smith } 8573aeaf226SBarry Smith } 8589566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc)); 8593aeaf226SBarry Smith 860f3fbd535SBarry Smith /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 861f3fbd535SBarry Smith /* so use those from global PC */ 862f3fbd535SBarry Smith /* Is this what we always want? What if user wants to keep old one? */ 8639566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset)); 86498e04984SBarry Smith if (opsset) { 86598e04984SBarry Smith Mat mmat; 8669566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat)); 86798e04984SBarry Smith if (mmat == pc->pmat) opsset = PETSC_FALSE; 86898e04984SBarry Smith } 8694a5f07a5SMark F. Adams 87041b6fd38SMatthew G. Knepley /* Create CR solvers */ 8719566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptCR(pc, &doCR)); 87241b6fd38SMatthew G. Knepley if (doCR) { 87341b6fd38SMatthew G. Knepley const char *prefix; 87441b6fd38SMatthew G. Knepley 8759566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 87641b6fd38SMatthew G. Knepley for (i = 1; i < n; ++i) { 87741b6fd38SMatthew G. Knepley PC ipc, cr; 87841b6fd38SMatthew G. Knepley char crprefix[128]; 87941b6fd38SMatthew G. Knepley 8809566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr)); 8813821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel)); 8829566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 8839566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i)); 8849566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 8859566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 8869566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 8879566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 8889566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 8899566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->cr, &ipc)); 89041b6fd38SMatthew G. Knepley 8919566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCCOMPOSITE)); 8929566063dSJacob Faibussowitsch PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 8939566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPCType(ipc, PCSOR)); 8949566063dSJacob Faibussowitsch PetscCall(CreateCR_Private(pc, i, &cr)); 8959566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPC(ipc, cr)); 8969566063dSJacob Faibussowitsch PetscCall(PCDestroy(&cr)); 89741b6fd38SMatthew G. Knepley 8989566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd)); 8999566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 9009566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int)i)); 9019566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 90241b6fd38SMatthew G. Knepley } 90341b6fd38SMatthew G. Knepley } 90441b6fd38SMatthew G. Knepley 9054a5f07a5SMark F. Adams if (!opsset) { 9069566063dSJacob Faibussowitsch PetscCall(PCGetUseAmat(pc, &use_amat)); 9074a5f07a5SMark F. Adams if (use_amat) { 9089566063dSJacob 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")); 9099566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat)); 91069858f1bSStefano Zampini } else { 9119566063dSJacob 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")); 9129566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat)); 9134a5f07a5SMark F. Adams } 9144a5f07a5SMark F. Adams } 915f3fbd535SBarry Smith 9169c7ffb39SBarry Smith for (i = n - 1; i > 0; i--) { 9179c7ffb39SBarry Smith if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 9189c7ffb39SBarry Smith missinginterpolate = PETSC_TRUE; 9192b3cbbdaSStefano Zampini break; 9209c7ffb39SBarry Smith } 9219c7ffb39SBarry Smith } 9222134b1e4SBarry Smith 9239566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB)); 9242134b1e4SBarry Smith if (dA == dB) dAeqdB = PETSC_TRUE; 9252b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) { 9262134b1e4SBarry Smith needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */ 9272134b1e4SBarry Smith } 9282134b1e4SBarry Smith 9292b3cbbdaSStefano Zampini if (pc->dm && !pc->setupcalled) { 9302b3cbbdaSStefano Zampini /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 9312b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm)); 9322b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE)); 9332b3cbbdaSStefano Zampini if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) { 9342b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm)); 9352b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE)); 9362b3cbbdaSStefano Zampini } 9372b3cbbdaSStefano Zampini if (mglevels[n - 1]->cr) { 9382b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm)); 9392b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE)); 9402b3cbbdaSStefano Zampini } 9412b3cbbdaSStefano Zampini } 9422b3cbbdaSStefano Zampini 9439c7ffb39SBarry Smith /* 9449c7ffb39SBarry Smith Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 9452b3cbbdaSStefano Zampini Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 9469c7ffb39SBarry Smith */ 94732fe681dSStefano Zampini if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 94832fe681dSStefano Zampini /* first see if we can compute a coarse space */ 94932fe681dSStefano Zampini if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) { 95032fe681dSStefano Zampini for (i = n - 2; i > -1; i--) { 95132fe681dSStefano Zampini if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) { 95232fe681dSStefano Zampini PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace)); 95332fe681dSStefano Zampini PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace)); 95432fe681dSStefano Zampini } 95532fe681dSStefano Zampini } 95632fe681dSStefano Zampini } else { /* construct the interpolation from the DMs */ 9572e499ae9SBarry Smith Mat p; 95873250ac0SBarry Smith Vec rscale; 9599566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &dms)); 960218a07d4SBarry Smith dms[n - 1] = pc->dm; 961ef1267afSMatthew G. Knepley /* Separately create them so we do not get DMKSP interference between levels */ 9629566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i])); 963218a07d4SBarry Smith for (i = n - 2; i > -1; i--) { 964942e3340SBarry Smith DMKSP kdm; 965eab52d2bSLawrence Mitchell PetscBool dmhasrestrict, dmhasinject; 9669566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i])); 9679566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE)); 968c27ee7a3SPatrick Farrell if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 9699566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i])); 9709566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE)); 971c27ee7a3SPatrick Farrell } 97241b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 9739566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->cr, dms[i])); 9749566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE)); 97541b6fd38SMatthew G. Knepley } 9769566063dSJacob Faibussowitsch PetscCall(DMGetDMKSPWrite(dms[i], &kdm)); 977d1a3e677SJed Brown /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 978d1a3e677SJed Brown * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 9790298fd71SBarry Smith kdm->ops->computerhs = NULL; 9800298fd71SBarry Smith kdm->rhsctx = NULL; 98124c3aa18SBarry Smith if (!mglevels[i + 1]->interpolate) { 9829566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale)); 9839566063dSJacob Faibussowitsch PetscCall(PCMGSetInterpolation(pc, i + 1, p)); 9849566063dSJacob Faibussowitsch if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale)); 9859566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rscale)); 9869566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 987218a07d4SBarry Smith } 9889566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict)); 9893ad4599aSBarry Smith if (dmhasrestrict && !mglevels[i + 1]->restrct) { 9909566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p)); 9919566063dSJacob Faibussowitsch PetscCall(PCMGSetRestriction(pc, i + 1, p)); 9929566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 9933ad4599aSBarry Smith } 9949566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(dms[i], &dmhasinject)); 995eab52d2bSLawrence Mitchell if (dmhasinject && !mglevels[i + 1]->inject) { 9969566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p)); 9979566063dSJacob Faibussowitsch PetscCall(PCMGSetInjection(pc, i + 1, p)); 9989566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 999eab52d2bSLawrence Mitchell } 100024c3aa18SBarry Smith } 10012d2b81a6SBarry Smith 10029566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i])); 10039566063dSJacob Faibussowitsch PetscCall(PetscFree(dms)); 1004ce4cda84SJed Brown } 100532fe681dSStefano Zampini } 1006cab2e9ccSBarry Smith 10072134b1e4SBarry Smith if (mg->galerkin < PC_MG_GALERKIN_NONE) { 10082134b1e4SBarry Smith Mat A, B; 10092134b1e4SBarry Smith PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE; 10102134b1e4SBarry Smith MatReuse reuse = MAT_INITIAL_MATRIX; 10112134b1e4SBarry Smith 10122b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE; 10132b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE; 10142134b1e4SBarry Smith if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 1015f3fbd535SBarry Smith for (i = n - 2; i > -1; i--) { 10167827d75bSBarry 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"); 101748a46eb9SPierre Jolivet if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct)); 101848a46eb9SPierre Jolivet if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate)); 101948a46eb9SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B)); 102048a46eb9SPierre Jolivet if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A)); 102148a46eb9SPierre Jolivet if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B)); 10222134b1e4SBarry Smith /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 10232134b1e4SBarry Smith if (!doA && dAeqdB) { 10249566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B)); 10252134b1e4SBarry Smith A = B; 10262134b1e4SBarry Smith } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 10279566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL)); 10289566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 1029b9367914SBarry Smith } 10302134b1e4SBarry Smith if (!doB && dAeqdB) { 10319566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A)); 10322134b1e4SBarry Smith B = A; 10332134b1e4SBarry Smith } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 10349566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B)); 10359566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 10367d537d92SJed Brown } 10372134b1e4SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 10389566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B)); 10399566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)A)); 10409566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)B)); 10412134b1e4SBarry Smith } 10422134b1e4SBarry Smith dA = A; 1043f3fbd535SBarry Smith dB = B; 1044f3fbd535SBarry Smith } 1045f3fbd535SBarry Smith } 1046f3b08a26SMatthew G. Knepley 1047f3b08a26SMatthew G. Knepley /* Adapt interpolation matrices */ 10482b3cbbdaSStefano Zampini if (adaptInterpolation) { 1049f3b08a26SMatthew G. Knepley for (i = 0; i < n; ++i) { 105048a46eb9SPierre Jolivet if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace)); 10512b3cbbdaSStefano Zampini if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace)); 1052f3b08a26SMatthew G. Knepley } 105348a46eb9SPierre Jolivet for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i)); 1054f3b08a26SMatthew G. Knepley } 1055f3b08a26SMatthew G. Knepley 10562134b1e4SBarry Smith if (needRestricts && pc->dm) { 1057caa4e7f2SJed Brown for (i = n - 2; i >= 0; i--) { 1058ccceb50cSJed Brown DM dmfine, dmcoarse; 1059caa4e7f2SJed Brown Mat Restrict, Inject; 1060caa4e7f2SJed Brown Vec rscale; 10619566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine)); 10629566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse)); 10639566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict)); 10649566063dSJacob Faibussowitsch PetscCall(PCMGGetRScale(pc, i + 1, &rscale)); 10659566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(pc, i + 1, &Inject)); 10669566063dSJacob Faibussowitsch PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse)); 1067caa4e7f2SJed Brown } 1068caa4e7f2SJed Brown } 1069f3fbd535SBarry Smith 1070f3fbd535SBarry Smith if (!pc->setupcalled) { 107148a46eb9SPierre Jolivet for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd)); 1072f3fbd535SBarry Smith for (i = 1; i < n; i++) { 107348a46eb9SPierre Jolivet if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu)); 107448a46eb9SPierre Jolivet if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr)); 1075f3fbd535SBarry Smith } 10763ad4599aSBarry Smith /* insure that if either interpolation or restriction is set the other other one is set */ 1077f3fbd535SBarry Smith for (i = 1; i < n; i++) { 10789566063dSJacob Faibussowitsch PetscCall(PCMGGetInterpolation(pc, i, NULL)); 10799566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i, NULL)); 1080f3fbd535SBarry Smith } 1081f3fbd535SBarry Smith for (i = 0; i < n - 1; i++) { 1082f3fbd535SBarry Smith if (!mglevels[i]->b) { 1083f3fbd535SBarry Smith Vec *vec; 10849566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL)); 10859566063dSJacob Faibussowitsch PetscCall(PCMGSetRhs(pc, i, *vec)); 10869566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 10879566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1088f3fbd535SBarry Smith } 1089f3fbd535SBarry Smith if (!mglevels[i]->r && i) { 10909566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 10919566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, i, tvec)); 10929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1093f3fbd535SBarry Smith } 1094f3fbd535SBarry Smith if (!mglevels[i]->x) { 10959566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 10969566063dSJacob Faibussowitsch PetscCall(PCMGSetX(pc, i, tvec)); 10979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1098f3fbd535SBarry Smith } 109941b6fd38SMatthew G. Knepley if (doCR) { 11009566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx)); 11019566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb)); 11029566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[i]->crb)); 110341b6fd38SMatthew G. Knepley } 1104f3fbd535SBarry Smith } 1105f3fbd535SBarry Smith if (n != 1 && !mglevels[n - 1]->r) { 1106f3fbd535SBarry Smith /* PCMGSetR() on the finest level if user did not supply it */ 1107f3fbd535SBarry Smith Vec *vec; 11089566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL)); 11099566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, n - 1, *vec)); 11109566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11119566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1112f3fbd535SBarry Smith } 111341b6fd38SMatthew G. Knepley if (doCR) { 11149566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx)); 11159566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb)); 11169566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[n - 1]->crb)); 111741b6fd38SMatthew G. Knepley } 1118f3fbd535SBarry Smith } 1119f3fbd535SBarry Smith 112098e04984SBarry Smith if (pc->dm) { 112198e04984SBarry Smith /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 112298e04984SBarry Smith for (i = 0; i < n - 1; i++) { 112398e04984SBarry Smith if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 112498e04984SBarry Smith } 112598e04984SBarry Smith } 112608549ed4SJed Brown // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g., 112708549ed4SJed Brown // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply. 112808549ed4SJed Brown if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1129f3fbd535SBarry Smith 1130f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11312a21e185SBarry Smith if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1132f3fbd535SBarry Smith /* if doing only down then initial guess is zero */ 11339566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1134f3fbd535SBarry Smith } 11359566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11369566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11379566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothd)); 1138d4645a75SStefano Zampini if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 11399566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1140d42688cbSBarry Smith if (!mglevels[i]->residual) { 1141d42688cbSBarry Smith Mat mat; 11429566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11439566063dSJacob Faibussowitsch PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat)); 1144d42688cbSBarry Smith } 1145fcb023d4SJed Brown if (!mglevels[i]->residualtranspose) { 1146fcb023d4SJed Brown Mat mat; 11479566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11489566063dSJacob Faibussowitsch PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat)); 1149fcb023d4SJed Brown } 1150f3fbd535SBarry Smith } 1151f3fbd535SBarry Smith for (i = 1; i < n; i++) { 1152f3fbd535SBarry Smith if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1153f3fbd535SBarry Smith Mat downmat, downpmat; 1154f3fbd535SBarry Smith 1155f3fbd535SBarry Smith /* check if operators have been set for up, if not use down operators to set them */ 11569566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL)); 1157f3fbd535SBarry Smith if (!opsset) { 11589566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11599566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat)); 1160f3fbd535SBarry Smith } 1161f3fbd535SBarry Smith 11629566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE)); 11639566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11649566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothu)); 1165d4645a75SStefano Zampini if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR; 11669566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1167f3fbd535SBarry Smith } 116841b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 116941b6fd38SMatthew G. Knepley Mat downmat, downpmat; 117041b6fd38SMatthew G. Knepley 117141b6fd38SMatthew G. Knepley /* check if operators have been set for up, if not use down operators to set them */ 11729566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL)); 117341b6fd38SMatthew G. Knepley if (!opsset) { 11749566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11759566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat)); 117641b6fd38SMatthew G. Knepley } 117741b6fd38SMatthew G. Knepley 11789566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11799566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11809566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->cr)); 1181d4645a75SStefano Zampini if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR; 11829566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 118341b6fd38SMatthew G. Knepley } 1184f3fbd535SBarry Smith } 1185f3fbd535SBarry Smith 11869566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 11879566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[0]->smoothd)); 1188d4645a75SStefano Zampini if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 11899566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1190f3fbd535SBarry Smith 1191f3fbd535SBarry Smith /* 1192f3fbd535SBarry Smith Dump the interpolation/restriction matrices plus the 1193e3c5b3baSBarry Smith Jacobian/stiffness on each level. This allows MATLAB users to 1194f3fbd535SBarry Smith easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1195f3fbd535SBarry Smith 1196f3fbd535SBarry Smith Only support one or the other at the same time. 1197f3fbd535SBarry Smith */ 1198f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER) 11999566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL)); 1200ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1201f3fbd535SBarry Smith dump = PETSC_FALSE; 1202f3fbd535SBarry Smith #endif 12039566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL)); 1204ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1205f3fbd535SBarry Smith 1206f3fbd535SBarry Smith if (viewer) { 120748a46eb9SPierre Jolivet for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer)); 1208f3fbd535SBarry Smith for (i = 0; i < n; i++) { 12099566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc)); 12109566063dSJacob Faibussowitsch PetscCall(MatView(pc->mat, viewer)); 1211f3fbd535SBarry Smith } 1212f3fbd535SBarry Smith } 12133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1214f3fbd535SBarry Smith } 1215f3fbd535SBarry Smith 1216d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 1217d71ae5a4SJacob Faibussowitsch { 121897d33e41SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 121997d33e41SMatthew G. Knepley 122097d33e41SMatthew G. Knepley PetscFunctionBegin; 122197d33e41SMatthew G. Knepley *levels = mg->nlevels; 12223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 122397d33e41SMatthew G. Knepley } 122497d33e41SMatthew G. Knepley 12254b9ad928SBarry Smith /*@ 1226f1580f4eSBarry Smith PCMGGetLevels - Gets the number of levels to use with `PCMG`. 12274b9ad928SBarry Smith 12284b9ad928SBarry Smith Not Collective 12294b9ad928SBarry Smith 12304b9ad928SBarry Smith Input Parameter: 12314b9ad928SBarry Smith . pc - the preconditioner context 12324b9ad928SBarry Smith 1233feefa0e1SJacob Faibussowitsch Output Parameter: 12344b9ad928SBarry Smith . levels - the number of levels 12354b9ad928SBarry Smith 12364b9ad928SBarry Smith Level: advanced 12374b9ad928SBarry Smith 1238f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetLevels()` 12394b9ad928SBarry Smith @*/ 1240d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) 1241d71ae5a4SJacob Faibussowitsch { 12424b9ad928SBarry Smith PetscFunctionBegin; 12430700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 12444f572ea9SToby Isaac PetscAssertPointer(levels, 2); 124597d33e41SMatthew G. Knepley *levels = 0; 1246cac4c232SBarry Smith PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels)); 12473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12484b9ad928SBarry Smith } 12494b9ad928SBarry Smith 12504b9ad928SBarry Smith /*@ 1251f1580f4eSBarry Smith PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy 1252e7d4b4cbSMark Adams 1253e7d4b4cbSMark Adams Input Parameter: 1254e7d4b4cbSMark Adams . pc - the preconditioner context 1255e7d4b4cbSMark Adams 125690db8557SMark Adams Output Parameters: 125790db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0 125890db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0 1259e7d4b4cbSMark Adams 1260e7d4b4cbSMark Adams Level: advanced 1261e7d4b4cbSMark Adams 1262f1580f4eSBarry Smith Note: 1263f1580f4eSBarry Smith This is often call the operator complexity in multigrid literature 1264f1580f4eSBarry Smith 1265f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()` 1266e7d4b4cbSMark Adams @*/ 1267d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) 1268d71ae5a4SJacob Faibussowitsch { 1269e7d4b4cbSMark Adams PC_MG *mg = (PC_MG *)pc->data; 1270e7d4b4cbSMark Adams PC_MG_Levels **mglevels = mg->levels; 1271e7d4b4cbSMark Adams PetscInt lev, N; 1272e7d4b4cbSMark Adams PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1273e7d4b4cbSMark Adams MatInfo info; 1274e7d4b4cbSMark Adams 1275e7d4b4cbSMark Adams PetscFunctionBegin; 127690db8557SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 12774f572ea9SToby Isaac if (gc) PetscAssertPointer(gc, 2); 12784f572ea9SToby Isaac if (oc) PetscAssertPointer(oc, 3); 1279e7d4b4cbSMark Adams if (!pc->setupcalled) { 128090db8557SMark Adams if (gc) *gc = 0; 128190db8557SMark Adams if (oc) *oc = 0; 12823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1283e7d4b4cbSMark Adams } 1284e7d4b4cbSMark Adams PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels"); 1285e7d4b4cbSMark Adams for (lev = 0; lev < mg->nlevels; lev++) { 1286e7d4b4cbSMark Adams Mat dB; 12879566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB)); 12889566063dSJacob Faibussowitsch PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */ 12899566063dSJacob Faibussowitsch PetscCall(MatGetSize(dB, &N, NULL)); 1290e7d4b4cbSMark Adams sgc += N; 1291e7d4b4cbSMark Adams soc += info.nz_used; 12929371c9d4SSatish Balay if (lev == mg->nlevels - 1) { 12939371c9d4SSatish Balay nnz0 = info.nz_used; 12949371c9d4SSatish Balay n0 = N; 12959371c9d4SSatish Balay } 1296e7d4b4cbSMark Adams } 12970fdf79fbSJacob Faibussowitsch PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available"); 12980fdf79fbSJacob Faibussowitsch *gc = (PetscReal)(sgc / n0); 129990db8557SMark Adams if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0); 13003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1301e7d4b4cbSMark Adams } 1302e7d4b4cbSMark Adams 1303e7d4b4cbSMark Adams /*@ 1304*04c3f3b8SBarry Smith PCMGSetType - Determines the form of multigrid to use, either 13054b9ad928SBarry Smith multiplicative, additive, full, or the Kaskade algorithm. 13064b9ad928SBarry Smith 1307c3339decSBarry Smith Logically Collective 13084b9ad928SBarry Smith 13094b9ad928SBarry Smith Input Parameters: 13104b9ad928SBarry Smith + pc - the preconditioner context 1311f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE` 13124b9ad928SBarry Smith 13134b9ad928SBarry Smith Options Database Key: 131420f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade 13154b9ad928SBarry Smith 13164b9ad928SBarry Smith Level: advanced 13174b9ad928SBarry Smith 1318f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType` 13194b9ad928SBarry Smith @*/ 1320d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form) 1321d71ae5a4SJacob Faibussowitsch { 1322f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 13234b9ad928SBarry Smith 13244b9ad928SBarry Smith PetscFunctionBegin; 13250700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1326c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc, form, 2); 132731567311SBarry Smith mg->am = form; 13289dcbbd2bSBarry Smith if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1329c60c7ad4SBarry Smith else pc->ops->applyrichardson = NULL; 13303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1331c60c7ad4SBarry Smith } 1332c60c7ad4SBarry Smith 1333c60c7ad4SBarry Smith /*@ 1334f1580f4eSBarry Smith PCMGGetType - Finds the form of multigrid the `PCMG` is using multiplicative, additive, full, or the Kaskade algorithm. 1335c60c7ad4SBarry Smith 1336c3339decSBarry Smith Logically Collective 1337c60c7ad4SBarry Smith 1338c60c7ad4SBarry Smith Input Parameter: 1339c60c7ad4SBarry Smith . pc - the preconditioner context 1340c60c7ad4SBarry Smith 1341c60c7ad4SBarry Smith Output Parameter: 1342f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType` 1343c60c7ad4SBarry Smith 1344c60c7ad4SBarry Smith Level: advanced 1345c60c7ad4SBarry Smith 1346f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()` 1347c60c7ad4SBarry Smith @*/ 1348d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type) 1349d71ae5a4SJacob Faibussowitsch { 1350c60c7ad4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1351c60c7ad4SBarry Smith 1352c60c7ad4SBarry Smith PetscFunctionBegin; 1353c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1354c60c7ad4SBarry Smith *type = mg->am; 13553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13564b9ad928SBarry Smith } 13574b9ad928SBarry Smith 13584b9ad928SBarry Smith /*@ 1359f1580f4eSBarry Smith PCMGSetCycleType - Sets the type cycles to use. Use `PCMGSetCycleTypeOnLevel()` for more 13604b9ad928SBarry Smith complicated cycling. 13614b9ad928SBarry Smith 1362c3339decSBarry Smith Logically Collective 13634b9ad928SBarry Smith 13644b9ad928SBarry Smith Input Parameters: 1365c2be2410SBarry Smith + pc - the multigrid context 1366f1580f4eSBarry Smith - n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 13674b9ad928SBarry Smith 13684b9ad928SBarry Smith Options Database Key: 1369c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired 13704b9ad928SBarry Smith 13714b9ad928SBarry Smith Level: advanced 13724b9ad928SBarry Smith 1373f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType` 13744b9ad928SBarry Smith @*/ 1375d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) 1376d71ae5a4SJacob Faibussowitsch { 1377f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1378f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 137979416396SBarry Smith PetscInt i, levels; 13804b9ad928SBarry Smith 13814b9ad928SBarry Smith PetscFunctionBegin; 13820700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 138369fbec6eSBarry Smith PetscValidLogicalCollectiveEnum(pc, n, 2); 138428b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1385f3fbd535SBarry Smith levels = mglevels[0]->levels; 13862fa5cd67SKarl Rupp for (i = 0; i < levels; i++) mglevels[i]->cycles = n; 13873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13884b9ad928SBarry Smith } 13894b9ad928SBarry Smith 13908cc2d5dfSBarry Smith /*@ 13918cc2d5dfSBarry Smith PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1392f1580f4eSBarry Smith of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE` 13938cc2d5dfSBarry Smith 1394c3339decSBarry Smith Logically Collective 13958cc2d5dfSBarry Smith 13968cc2d5dfSBarry Smith Input Parameters: 13978cc2d5dfSBarry Smith + pc - the multigrid context 13988cc2d5dfSBarry Smith - n - number of cycles (default is 1) 13998cc2d5dfSBarry Smith 14008cc2d5dfSBarry Smith Options Database Key: 1401147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles 14028cc2d5dfSBarry Smith 14038cc2d5dfSBarry Smith Level: advanced 14048cc2d5dfSBarry Smith 1405f1580f4eSBarry Smith Note: 1406f1580f4eSBarry Smith This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()` 14078cc2d5dfSBarry Smith 1408f1580f4eSBarry Smith .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType` 14098cc2d5dfSBarry Smith @*/ 1410d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) 1411d71ae5a4SJacob Faibussowitsch { 1412f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14138cc2d5dfSBarry Smith 14148cc2d5dfSBarry Smith PetscFunctionBegin; 14150700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1416c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 14172a21e185SBarry Smith mg->cyclesperpcapply = n; 14183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14198cc2d5dfSBarry Smith } 14208cc2d5dfSBarry Smith 1421d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) 1422d71ae5a4SJacob Faibussowitsch { 1423fb15c04eSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1424fb15c04eSBarry Smith 1425fb15c04eSBarry Smith PetscFunctionBegin; 14262134b1e4SBarry Smith mg->galerkin = use; 14273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1428fb15c04eSBarry Smith } 1429fb15c04eSBarry Smith 1430c2be2410SBarry Smith /*@ 143197177400SBarry Smith PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 143282b87d87SMatthew G. Knepley finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1433c2be2410SBarry Smith 1434c3339decSBarry Smith Logically Collective 1435c2be2410SBarry Smith 1436c2be2410SBarry Smith Input Parameters: 1437c91913d3SJed Brown + pc - the multigrid context 1438f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE` 1439c2be2410SBarry Smith 1440c2be2410SBarry Smith Options Database Key: 1441147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1442c2be2410SBarry Smith 1443c2be2410SBarry Smith Level: intermediate 1444c2be2410SBarry Smith 1445f1580f4eSBarry Smith Note: 1446f1580f4eSBarry Smith Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not 1447f1580f4eSBarry Smith use the `PCMG` construction of the coarser grids. 14481c1aac46SBarry Smith 1449f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType` 1450c2be2410SBarry Smith @*/ 1451d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) 1452d71ae5a4SJacob Faibussowitsch { 1453c2be2410SBarry Smith PetscFunctionBegin; 14540700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1455cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use)); 14563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1457c2be2410SBarry Smith } 1458c2be2410SBarry Smith 14593fc8bf9cSBarry Smith /*@ 1460f1580f4eSBarry Smith PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i 14613fc8bf9cSBarry Smith 14623fc8bf9cSBarry Smith Not Collective 14633fc8bf9cSBarry Smith 14643fc8bf9cSBarry Smith Input Parameter: 14653fc8bf9cSBarry Smith . pc - the multigrid context 14663fc8bf9cSBarry Smith 14673fc8bf9cSBarry Smith Output Parameter: 1468f1580f4eSBarry 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` 14693fc8bf9cSBarry Smith 14703fc8bf9cSBarry Smith Level: intermediate 14713fc8bf9cSBarry Smith 1472f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType` 14733fc8bf9cSBarry Smith @*/ 1474d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) 1475d71ae5a4SJacob Faibussowitsch { 1476f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14773fc8bf9cSBarry Smith 14783fc8bf9cSBarry Smith PetscFunctionBegin; 14790700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 14802134b1e4SBarry Smith *galerkin = mg->galerkin; 14813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14823fc8bf9cSBarry Smith } 14833fc8bf9cSBarry Smith 1484d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) 1485d71ae5a4SJacob Faibussowitsch { 1486f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1487f3b08a26SMatthew G. Knepley 1488f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1489f3b08a26SMatthew G. Knepley mg->adaptInterpolation = adapt; 14903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1491f3b08a26SMatthew G. Knepley } 1492f3b08a26SMatthew G. Knepley 1493d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) 1494d71ae5a4SJacob Faibussowitsch { 1495f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1496f3b08a26SMatthew G. Knepley 1497f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1498f3b08a26SMatthew G. Knepley *adapt = mg->adaptInterpolation; 14993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1500f3b08a26SMatthew G. Knepley } 1501f3b08a26SMatthew G. Knepley 1502d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) 1503d71ae5a4SJacob Faibussowitsch { 15042b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15052b3cbbdaSStefano Zampini 15062b3cbbdaSStefano Zampini PetscFunctionBegin; 15072b3cbbdaSStefano Zampini mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE; 15082b3cbbdaSStefano Zampini mg->coarseSpaceType = ctype; 15093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15102b3cbbdaSStefano Zampini } 15112b3cbbdaSStefano Zampini 1512d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) 1513d71ae5a4SJacob Faibussowitsch { 15142b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15152b3cbbdaSStefano Zampini 15162b3cbbdaSStefano Zampini PetscFunctionBegin; 15172b3cbbdaSStefano Zampini *ctype = mg->coarseSpaceType; 15183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15192b3cbbdaSStefano Zampini } 15202b3cbbdaSStefano Zampini 1521d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) 1522d71ae5a4SJacob Faibussowitsch { 152341b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 152441b6fd38SMatthew G. Knepley 152541b6fd38SMatthew G. Knepley PetscFunctionBegin; 152641b6fd38SMatthew G. Knepley mg->compatibleRelaxation = cr; 15273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 152841b6fd38SMatthew G. Knepley } 152941b6fd38SMatthew G. Knepley 1530d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) 1531d71ae5a4SJacob Faibussowitsch { 153241b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 153341b6fd38SMatthew G. Knepley 153441b6fd38SMatthew G. Knepley PetscFunctionBegin; 153541b6fd38SMatthew G. Knepley *cr = mg->compatibleRelaxation; 15363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 153741b6fd38SMatthew G. Knepley } 153841b6fd38SMatthew G. Knepley 15392b3cbbdaSStefano Zampini /*@C 15402b3cbbdaSStefano Zampini PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space. 15412b3cbbdaSStefano Zampini 15422b3cbbdaSStefano 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. 15432b3cbbdaSStefano Zampini 1544c3339decSBarry Smith Logically Collective 15452b3cbbdaSStefano Zampini 15462b3cbbdaSStefano Zampini Input Parameters: 15472b3cbbdaSStefano Zampini + pc - the multigrid context 15482b3cbbdaSStefano Zampini - ctype - the type of coarse space 15492b3cbbdaSStefano Zampini 15502b3cbbdaSStefano Zampini Options Database Keys: 15512b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int> - The number of modes to use 15522b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw 15532b3cbbdaSStefano Zampini 15542b3cbbdaSStefano Zampini Level: intermediate 15552b3cbbdaSStefano Zampini 1556f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()` 15572b3cbbdaSStefano Zampini @*/ 1558d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) 1559d71ae5a4SJacob Faibussowitsch { 15602b3cbbdaSStefano Zampini PetscFunctionBegin; 15612b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15622b3cbbdaSStefano Zampini PetscValidLogicalCollectiveEnum(pc, ctype, 2); 15632b3cbbdaSStefano Zampini PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype)); 15643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15652b3cbbdaSStefano Zampini } 15662b3cbbdaSStefano Zampini 15672b3cbbdaSStefano Zampini /*@C 15682b3cbbdaSStefano Zampini PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space. 15692b3cbbdaSStefano Zampini 15702b3cbbdaSStefano Zampini Not Collective 15712b3cbbdaSStefano Zampini 15722b3cbbdaSStefano Zampini Input Parameter: 15732b3cbbdaSStefano Zampini . pc - the multigrid context 15742b3cbbdaSStefano Zampini 15752b3cbbdaSStefano Zampini Output Parameter: 15762b3cbbdaSStefano Zampini . ctype - the type of coarse space 15772b3cbbdaSStefano Zampini 15782b3cbbdaSStefano Zampini Level: intermediate 15792b3cbbdaSStefano Zampini 1580f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()` 15812b3cbbdaSStefano Zampini @*/ 1582d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) 1583d71ae5a4SJacob Faibussowitsch { 15842b3cbbdaSStefano Zampini PetscFunctionBegin; 15852b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15864f572ea9SToby Isaac PetscAssertPointer(ctype, 2); 15872b3cbbdaSStefano Zampini PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype)); 15883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15892b3cbbdaSStefano Zampini } 15902b3cbbdaSStefano Zampini 15912b3cbbdaSStefano Zampini /* MATT: REMOVE? */ 1592f3b08a26SMatthew G. Knepley /*@ 1593f3b08a26SMatthew 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. 1594f3b08a26SMatthew G. Knepley 1595c3339decSBarry Smith Logically Collective 1596f3b08a26SMatthew G. Knepley 1597f3b08a26SMatthew G. Knepley Input Parameters: 1598f3b08a26SMatthew G. Knepley + pc - the multigrid context 1599f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator 1600f3b08a26SMatthew G. Knepley 1601f3b08a26SMatthew G. Knepley Options Database Keys: 1602f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp - Turn on adaptation 1603f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1604f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1605f3b08a26SMatthew G. Knepley 1606f3b08a26SMatthew G. Knepley Level: intermediate 1607f3b08a26SMatthew G. Knepley 1608f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1609f3b08a26SMatthew G. Knepley @*/ 1610d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) 1611d71ae5a4SJacob Faibussowitsch { 1612f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1613f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1614cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt)); 16153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1616f3b08a26SMatthew G. Knepley } 1617f3b08a26SMatthew G. Knepley 1618f3b08a26SMatthew G. Knepley /*@ 1619f1580f4eSBarry Smith PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, 1620f1580f4eSBarry Smith and thus accurately interpolated. 1621f3b08a26SMatthew G. Knepley 162220f4b53cSBarry Smith Not Collective 1623f3b08a26SMatthew G. Knepley 1624f3b08a26SMatthew G. Knepley Input Parameter: 1625f3b08a26SMatthew G. Knepley . pc - the multigrid context 1626f3b08a26SMatthew G. Knepley 1627f3b08a26SMatthew G. Knepley Output Parameter: 1628f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator 1629f3b08a26SMatthew G. Knepley 1630f3b08a26SMatthew G. Knepley Level: intermediate 1631f3b08a26SMatthew G. Knepley 1632f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1633f3b08a26SMatthew G. Knepley @*/ 1634d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) 1635d71ae5a4SJacob Faibussowitsch { 1636f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1637f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16384f572ea9SToby Isaac PetscAssertPointer(adapt, 2); 1639cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt)); 16403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1641f3b08a26SMatthew G. Knepley } 1642f3b08a26SMatthew G. Knepley 16434b9ad928SBarry Smith /*@ 164441b6fd38SMatthew G. Knepley PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 164541b6fd38SMatthew G. Knepley 1646c3339decSBarry Smith Logically Collective 164741b6fd38SMatthew G. Knepley 164841b6fd38SMatthew G. Knepley Input Parameters: 164941b6fd38SMatthew G. Knepley + pc - the multigrid context 165041b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation 165141b6fd38SMatthew G. Knepley 1652f1580f4eSBarry Smith Options Database Key: 165341b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation 165441b6fd38SMatthew G. Knepley 165541b6fd38SMatthew G. Knepley Level: intermediate 165641b6fd38SMatthew G. Knepley 1657f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 165841b6fd38SMatthew G. Knepley @*/ 1659d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) 1660d71ae5a4SJacob Faibussowitsch { 166141b6fd38SMatthew G. Knepley PetscFunctionBegin; 166241b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1663cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr)); 16643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 166541b6fd38SMatthew G. Knepley } 166641b6fd38SMatthew G. Knepley 166741b6fd38SMatthew G. Knepley /*@ 166841b6fd38SMatthew G. Knepley PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 166941b6fd38SMatthew G. Knepley 167020f4b53cSBarry Smith Not Collective 167141b6fd38SMatthew G. Knepley 167241b6fd38SMatthew G. Knepley Input Parameter: 167341b6fd38SMatthew G. Knepley . pc - the multigrid context 167441b6fd38SMatthew G. Knepley 167541b6fd38SMatthew G. Knepley Output Parameter: 167641b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion 167741b6fd38SMatthew G. Knepley 167841b6fd38SMatthew G. Knepley Level: intermediate 167941b6fd38SMatthew G. Knepley 1680f1580f4eSBarry Smith .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 168141b6fd38SMatthew G. Knepley @*/ 1682d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) 1683d71ae5a4SJacob Faibussowitsch { 168441b6fd38SMatthew G. Knepley PetscFunctionBegin; 168541b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16864f572ea9SToby Isaac PetscAssertPointer(cr, 2); 1687cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr)); 16883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 168941b6fd38SMatthew G. Knepley } 169041b6fd38SMatthew G. Knepley 169141b6fd38SMatthew G. Knepley /*@ 169206792cafSBarry Smith PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1693f1580f4eSBarry Smith on all levels. Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of 1694710315b6SLawrence Mitchell pre- and post-smoothing steps. 169506792cafSBarry Smith 1696c3339decSBarry Smith Logically Collective 169706792cafSBarry Smith 169806792cafSBarry Smith Input Parameters: 1699feefa0e1SJacob Faibussowitsch + pc - the multigrid context 170006792cafSBarry Smith - n - the number of smoothing steps 170106792cafSBarry Smith 170206792cafSBarry Smith Options Database Key: 1703a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 170406792cafSBarry Smith 170506792cafSBarry Smith Level: advanced 170606792cafSBarry Smith 1707f1580f4eSBarry Smith Note: 1708f1580f4eSBarry Smith This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid. 170906792cafSBarry Smith 1710f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetDistinctSmoothUp()` 171106792cafSBarry Smith @*/ 1712d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) 1713d71ae5a4SJacob Faibussowitsch { 171406792cafSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 171506792cafSBarry Smith PC_MG_Levels **mglevels = mg->levels; 171606792cafSBarry Smith PetscInt i, levels; 171706792cafSBarry Smith 171806792cafSBarry Smith PetscFunctionBegin; 171906792cafSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 172006792cafSBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 172128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 172206792cafSBarry Smith levels = mglevels[0]->levels; 172306792cafSBarry Smith 172406792cafSBarry Smith for (i = 1; i < levels; i++) { 17259566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n)); 17269566063dSJacob Faibussowitsch PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n)); 172706792cafSBarry Smith mg->default_smoothu = n; 172806792cafSBarry Smith mg->default_smoothd = n; 172906792cafSBarry Smith } 17303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 173106792cafSBarry Smith } 173206792cafSBarry Smith 1733f442ab6aSBarry Smith /*@ 1734f1580f4eSBarry Smith PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels 1735710315b6SLawrence Mitchell and adds the suffix _up to the options name 1736f442ab6aSBarry Smith 1737c3339decSBarry Smith Logically Collective 1738f442ab6aSBarry Smith 1739f1580f4eSBarry Smith Input Parameter: 1740f442ab6aSBarry Smith . pc - the preconditioner context 1741f442ab6aSBarry Smith 1742f442ab6aSBarry Smith Options Database Key: 1743147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1744f442ab6aSBarry Smith 1745f442ab6aSBarry Smith Level: advanced 1746f442ab6aSBarry Smith 1747f1580f4eSBarry Smith Note: 1748f1580f4eSBarry Smith This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid. 1749f442ab6aSBarry Smith 1750f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetNumberSmooth()` 1751f442ab6aSBarry Smith @*/ 1752d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1753d71ae5a4SJacob Faibussowitsch { 1754f442ab6aSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1755f442ab6aSBarry Smith PC_MG_Levels **mglevels = mg->levels; 1756f442ab6aSBarry Smith PetscInt i, levels; 1757f442ab6aSBarry Smith KSP subksp; 1758f442ab6aSBarry Smith 1759f442ab6aSBarry Smith PetscFunctionBegin; 1760f442ab6aSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 176128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1762f442ab6aSBarry Smith levels = mglevels[0]->levels; 1763f442ab6aSBarry Smith 1764f442ab6aSBarry Smith for (i = 1; i < levels; i++) { 1765710315b6SLawrence Mitchell const char *prefix = NULL; 1766f442ab6aSBarry Smith /* make sure smoother up and down are different */ 17679566063dSJacob Faibussowitsch PetscCall(PCMGGetSmootherUp(pc, i, &subksp)); 17689566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix)); 17699566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(subksp, prefix)); 17709566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(subksp, "up_")); 1771f442ab6aSBarry Smith } 17723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1773f442ab6aSBarry Smith } 1774f442ab6aSBarry Smith 177507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1776d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) 1777d71ae5a4SJacob Faibussowitsch { 177807a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 177907a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 178007a4832bSFande Kong Mat *mat; 178107a4832bSFande Kong PetscInt l; 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 = 1; l < mg->nlevels; l++) { 178707a4832bSFande Kong mat[l - 1] = mglevels[l]->interpolate; 17889566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l - 1])); 178907a4832bSFande Kong } 179007a4832bSFande Kong *num_levels = mg->nlevels; 179107a4832bSFande Kong *interpolations = mat; 17923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 179307a4832bSFande Kong } 179407a4832bSFande Kong 179507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1796d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) 1797d71ae5a4SJacob Faibussowitsch { 179807a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 179907a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 180007a4832bSFande Kong PetscInt l; 180107a4832bSFande Kong Mat *mat; 180207a4832bSFande Kong 180307a4832bSFande Kong PetscFunctionBegin; 180428b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 18059566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 180607a4832bSFande Kong for (l = 0; l < mg->nlevels - 1; l++) { 18079566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &(mat[l]))); 18089566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l])); 180907a4832bSFande Kong } 181007a4832bSFande Kong *num_levels = mg->nlevels; 181107a4832bSFande Kong *coarseOperators = mat; 18123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 181307a4832bSFande Kong } 181407a4832bSFande Kong 1815f3b08a26SMatthew G. Knepley /*@C 1816f1580f4eSBarry Smith PCMGRegisterCoarseSpaceConstructor - Adds a method to the `PCMG` package for coarse space construction. 1817f3b08a26SMatthew G. Knepley 181820f4b53cSBarry Smith Not Collective 1819f3b08a26SMatthew G. Knepley 1820f3b08a26SMatthew G. Knepley Input Parameters: 1821f3b08a26SMatthew G. Knepley + name - name of the constructor 1822f3b08a26SMatthew G. Knepley - function - constructor routine 1823f3b08a26SMatthew G. Knepley 182420f4b53cSBarry Smith Calling sequence of `function`: 182520f4b53cSBarry Smith + pc - The `PC` object 1826f1580f4eSBarry Smith . l - The multigrid level, 0 is the coarse level 182720f4b53cSBarry Smith . dm - The `DM` for this level 1828f1580f4eSBarry Smith . smooth - The level smoother 1829f1580f4eSBarry Smith . Nc - The size of the coarse space 1830f1580f4eSBarry Smith . initGuess - Basis for an initial guess for the space 1831f1580f4eSBarry Smith - coarseSp - A basis for the computed coarse space 1832f3b08a26SMatthew G. Knepley 1833f3b08a26SMatthew G. Knepley Level: advanced 1834f3b08a26SMatthew G. Knepley 1835feefa0e1SJacob Faibussowitsch Developer Notes: 1836f1580f4eSBarry Smith How come this is not used by `PCGAMG`? 1837f1580f4eSBarry Smith 1838f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()` 1839f3b08a26SMatthew G. Knepley @*/ 1840*04c3f3b8SBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)) 1841d71ae5a4SJacob Faibussowitsch { 1842f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18439566063dSJacob Faibussowitsch PetscCall(PCInitializePackage()); 18449566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function)); 18453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1846f3b08a26SMatthew G. Knepley } 1847f3b08a26SMatthew G. Knepley 1848f3b08a26SMatthew G. Knepley /*@C 1849f3b08a26SMatthew G. Knepley PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1850f3b08a26SMatthew G. Knepley 185120f4b53cSBarry Smith Not Collective 1852f3b08a26SMatthew G. Knepley 1853f3b08a26SMatthew G. Knepley Input Parameter: 1854f3b08a26SMatthew G. Knepley . name - name of the constructor 1855f3b08a26SMatthew G. Knepley 1856f3b08a26SMatthew G. Knepley Output Parameter: 1857f3b08a26SMatthew G. Knepley . function - constructor routine 1858f3b08a26SMatthew G. Knepley 1859f3b08a26SMatthew G. Knepley Level: advanced 1860f3b08a26SMatthew G. Knepley 1861f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()` 1862f3b08a26SMatthew G. Knepley @*/ 1863d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) 1864d71ae5a4SJacob Faibussowitsch { 1865f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18669566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function)); 18673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1868f3b08a26SMatthew G. Knepley } 1869f3b08a26SMatthew G. Knepley 18703b09bd56SBarry Smith /*MC 1871ccb205f8SBarry Smith PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 18723b09bd56SBarry Smith information about the coarser grid matrices and restriction/interpolation operators. 18733b09bd56SBarry Smith 18743b09bd56SBarry Smith Options Database Keys: 18753b09bd56SBarry Smith + -pc_mg_levels <nlevels> - number of levels including finest 1876391689abSStefano Zampini . -pc_mg_cycle_type <v,w> - provide the cycle desired 18778c1c2452SJed Brown . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 18783b09bd56SBarry Smith . -pc_mg_log - log information about time spent on each level of the solver 1879710315b6SLawrence Mitchell . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 18802134b1e4SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 18818cf6037eSBarry Smith . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 18828cf6037eSBarry Smith . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1883e3c5b3baSBarry Smith to the Socket viewer for reading from MATLAB. 18848cf6037eSBarry Smith - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 18858cf6037eSBarry Smith to the binary output file called binaryoutput 18863b09bd56SBarry Smith 188720f4b53cSBarry Smith Level: intermediate 188820f4b53cSBarry Smith 188995452b02SPatrick Sanan Notes: 1890*04c3f3b8SBarry Smith The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard 1891*04c3f3b8SBarry Smith options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`. 1892*04c3f3b8SBarry Smith One can set different preconditioners etc on specific levels with the prefix `-mg_levels_n_` where `n` is the level number (zero being 1893*04c3f3b8SBarry Smith the coarse level. For example 1894*04c3f3b8SBarry Smith .vb 1895*04c3f3b8SBarry Smith -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor 1896*04c3f3b8SBarry Smith .ve 1897*04c3f3b8SBarry Smith These options also work for controlling the smoothers etc inside `PCGAMG` 1898*04c3f3b8SBarry Smith 1899f1580f4eSBarry Smith If one uses a Krylov method such `KSPGMRES` or `KSPCG` as the smoother then one must use `KSPFGMRES`, `KSPGCR`, or `KSPRICHARDSON` as the outer Krylov method 19003b09bd56SBarry Smith 19018cf6037eSBarry Smith When run with a single level the smoother options are used on that level NOT the coarse grid solver options 19028cf6037eSBarry Smith 1903f1580f4eSBarry Smith When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 190423067569SBarry Smith is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 190523067569SBarry Smith (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 190623067569SBarry Smith residual is computed at the end of each cycle. 190723067569SBarry Smith 1908*04c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE` 1909db781477SPatrick Sanan `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`, 1910db781477SPatrick Sanan `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`, 1911db781477SPatrick Sanan `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, 1912f1580f4eSBarry Smith `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`, 1913f1580f4eSBarry Smith `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 19143b09bd56SBarry Smith M*/ 19153b09bd56SBarry Smith 1916d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1917d71ae5a4SJacob Faibussowitsch { 1918f3fbd535SBarry Smith PC_MG *mg; 1919f3fbd535SBarry Smith 19204b9ad928SBarry Smith PetscFunctionBegin; 19214dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mg)); 19223ec1f749SStefano Zampini pc->data = mg; 1923f3fbd535SBarry Smith mg->nlevels = -1; 192410eca3edSLisandro Dalcin mg->am = PC_MG_MULTIPLICATIVE; 19252134b1e4SBarry Smith mg->galerkin = PC_MG_GALERKIN_NONE; 1926f3b08a26SMatthew G. Knepley mg->adaptInterpolation = PETSC_FALSE; 1927f3b08a26SMatthew G. Knepley mg->Nc = -1; 1928f3b08a26SMatthew G. Knepley mg->eigenvalue = -1; 1929f3fbd535SBarry Smith 193037a44384SMark Adams pc->useAmat = PETSC_TRUE; 193137a44384SMark Adams 19324b9ad928SBarry Smith pc->ops->apply = PCApply_MG; 1933fcb023d4SJed Brown pc->ops->applytranspose = PCApplyTranspose_MG; 193430b0564aSStefano Zampini pc->ops->matapply = PCMatApply_MG; 19354b9ad928SBarry Smith pc->ops->setup = PCSetUp_MG; 1936a06653b4SBarry Smith pc->ops->reset = PCReset_MG; 19374b9ad928SBarry Smith pc->ops->destroy = PCDestroy_MG; 19384b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_MG; 19394b9ad928SBarry Smith pc->ops->view = PCView_MG; 1940fb15c04eSBarry Smith 19419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue)); 19429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG)); 19439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG)); 19449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG)); 19459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG)); 19469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG)); 19479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG)); 19489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG)); 19499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG)); 19509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG)); 19512b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG)); 19522b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG)); 19533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19544b9ad928SBarry Smith } 1955