14b9ad928SBarry Smith /* 24b9ad928SBarry Smith Defines the multigrid preconditioner interface. 34b9ad928SBarry Smith */ 4af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 541b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h> 61e25c274SJed Brown #include <petscdm.h> 7391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *); 84b9ad928SBarry Smith 9f3b08a26SMatthew G. Knepley /* 10f3b08a26SMatthew G. Knepley Contains the list of registered coarse space construction routines 11f3b08a26SMatthew G. Knepley */ 12f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL; 13f3b08a26SMatthew G. Knepley 14d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) 15d71ae5a4SJacob Faibussowitsch { 1631567311SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1731567311SBarry Smith PC_MG_Levels *mgc, *mglevels = *mglevelsin; 18835f2295SStefano Zampini PetscInt cycles = (mglevels->level == 1) ? 1 : mglevels->cycles; 194b9ad928SBarry Smith 204b9ad928SBarry Smith PetscFunctionBegin; 219566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 22fcb023d4SJed Brown if (!transpose) { 2330b0564aSStefano Zampini if (matapp) { 249566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */ 259566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL)); 2630b0564aSStefano Zampini } else { 279566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */ 289566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 2930b0564aSStefano Zampini } 30fcb023d4SJed Brown } else { 3128b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 329566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */ 339566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 34fcb023d4SJed Brown } 359566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 3631567311SBarry Smith if (mglevels->level) { /* not the coarsest grid */ 379566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0)); 3848a46eb9SPierre Jolivet if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R)); 39fcb023d4SJed Brown if (!transpose) { 409566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 419566063dSJacob Faibussowitsch else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 42fcb023d4SJed Brown } else { 439566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 449566063dSJacob Faibussowitsch else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 45fcb023d4SJed Brown } 469566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0)); 474b9ad928SBarry Smith 484b9ad928SBarry Smith /* if on finest level and have convergence criteria set */ 4931567311SBarry Smith if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) { 504b9ad928SBarry Smith PetscReal rnorm; 519566063dSJacob Faibussowitsch PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm)); 524b9ad928SBarry Smith if (rnorm <= mg->ttol) { 5370441072SBarry Smith if (rnorm < mg->abstol) { 544d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_ATOL; 559566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol)); 564b9ad928SBarry Smith } else { 574d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_RTOL; 589566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n", (double)rnorm, (double)mg->ttol)); 594b9ad928SBarry Smith } 603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 614b9ad928SBarry Smith } 624b9ad928SBarry Smith } 634b9ad928SBarry Smith 6431567311SBarry Smith mgc = *(mglevelsin - 1); 659566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 66fcb023d4SJed Brown if (!transpose) { 679566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B)); 689566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b)); 69fcb023d4SJed Brown } else { 709566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B)); 719566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b)); 72fcb023d4SJed Brown } 739566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 7430b0564aSStefano Zampini if (matapp) { 7530b0564aSStefano Zampini if (!mgc->X) { 769566063dSJacob Faibussowitsch PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X)); 7730b0564aSStefano Zampini } else { 789566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mgc->X)); 7930b0564aSStefano Zampini } 8030b0564aSStefano Zampini } else { 819566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mgc->x)); 8230b0564aSStefano Zampini } 8348a46eb9SPierre Jolivet while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason)); 849566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 85fcb023d4SJed Brown if (!transpose) { 869566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X)); 879566063dSJacob Faibussowitsch else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x)); 88fcb023d4SJed Brown } else { 899566063dSJacob Faibussowitsch PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x)); 90fcb023d4SJed Brown } 919566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 929566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 93fcb023d4SJed Brown if (!transpose) { 9430b0564aSStefano Zampini if (matapp) { 959566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */ 969566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL)); 9730b0564aSStefano Zampini } else { 989566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */ 999566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 10030b0564aSStefano Zampini } 101fcb023d4SJed Brown } else { 10228b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 1039566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */ 1049566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 105fcb023d4SJed Brown } 10641b6fd38SMatthew G. Knepley if (mglevels->cr) { 10720654ebbSStefano Zampini Mat crA; 10820654ebbSStefano Zampini 10928b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 11041b6fd38SMatthew G. Knepley /* TODO Turn on copy and turn off noisy if we have an exact solution 1119566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->x, mglevels->crx)); 1129566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->b, mglevels->crb)); */ 11320654ebbSStefano Zampini PetscCall(KSPGetOperators(mglevels->cr, &crA, NULL)); 11420654ebbSStefano Zampini PetscCall(KSPSetNoisy_Private(crA, mglevels->crx)); 1159566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */ 1169566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx)); 11741b6fd38SMatthew G. Knepley } 1189566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 1194b9ad928SBarry Smith } 1203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1214b9ad928SBarry Smith } 1224b9ad928SBarry Smith 123d71ae5a4SJacob 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) 124d71ae5a4SJacob Faibussowitsch { 125f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 126f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 127391689abSStefano Zampini PC tpc; 128391689abSStefano Zampini PetscBool changeu, changed; 129f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 1304b9ad928SBarry Smith 1314b9ad928SBarry Smith PetscFunctionBegin; 132a762d673SBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 133a762d673SBarry Smith for (i = 0; i < levels; i++) { 134a762d673SBarry Smith if (!mglevels[i]->A) { 1359566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 1369566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 137a762d673SBarry Smith } 138a762d673SBarry Smith } 139391689abSStefano Zampini 1409566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 1419566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 1429566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 1439566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 144391689abSStefano Zampini if (!changed && !changeu) { 1459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 146f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 147391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 148391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 149391689abSStefano Zampini Vec *vec; 150391689abSStefano Zampini 1519566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 152391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 1539566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 154391689abSStefano Zampini } 1559566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 156391689abSStefano Zampini } 157f3fbd535SBarry Smith mglevels[levels - 1]->x = x; 1584b9ad928SBarry Smith 15931567311SBarry Smith mg->rtol = rtol; 16031567311SBarry Smith mg->abstol = abstol; 16131567311SBarry Smith mg->dtol = dtol; 1624b9ad928SBarry Smith if (rtol) { 1634b9ad928SBarry Smith /* compute initial residual norm for relative convergence test */ 1644b9ad928SBarry Smith PetscReal rnorm; 1657319c654SBarry Smith if (zeroguess) { 1669566063dSJacob Faibussowitsch PetscCall(VecNorm(b, NORM_2, &rnorm)); 1677319c654SBarry Smith } else { 1689566063dSJacob Faibussowitsch PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w)); 1699566063dSJacob Faibussowitsch PetscCall(VecNorm(w, NORM_2, &rnorm)); 1707319c654SBarry Smith } 17131567311SBarry Smith mg->ttol = PetscMax(rtol * rnorm, abstol); 1722fa5cd67SKarl Rupp } else if (abstol) mg->ttol = abstol; 1732fa5cd67SKarl Rupp else mg->ttol = 0.0; 1744b9ad928SBarry Smith 1754d0a8057SBarry Smith /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 176336babb1SJed Brown stop prematurely due to small residual */ 1774d0a8057SBarry Smith for (i = 1; i < levels; i++) { 178fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT)); 179f3fbd535SBarry Smith if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 18023067569SBarry Smith /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */ 1819566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 182fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT)); 1834b9ad928SBarry Smith } 1844d0a8057SBarry Smith } 1854d0a8057SBarry Smith 186dd460d27SBarry Smith *reason = PCRICHARDSON_NOT_SET; 1874d0a8057SBarry Smith for (i = 0; i < its; i++) { 1889566063dSJacob Faibussowitsch PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason)); 1894d0a8057SBarry Smith if (*reason) break; 1904d0a8057SBarry Smith } 191dd460d27SBarry Smith if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS; 1924d0a8057SBarry Smith *outits = i; 193391689abSStefano Zampini if (!changed && !changeu) mglevels[levels - 1]->b = NULL; 1943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1954b9ad928SBarry Smith } 1964b9ad928SBarry Smith 197d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc) 198d71ae5a4SJacob Faibussowitsch { 1993aeaf226SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 2003aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 2012b3cbbdaSStefano Zampini PetscInt i, n; 2023aeaf226SBarry Smith 2033aeaf226SBarry Smith PetscFunctionBegin; 2043aeaf226SBarry Smith if (mglevels) { 2053aeaf226SBarry Smith n = mglevels[0]->levels; 2063aeaf226SBarry Smith for (i = 0; i < n - 1; i++) { 2079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->r)); 2089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->b)); 2099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->x)); 2109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->R)); 2119566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 2129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 2139566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crx)); 2149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crb)); 2159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->restrct)); 2169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->interpolate)); 2179566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->inject)); 2189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->rscale)); 2193aeaf226SBarry Smith } 2209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crx)); 2219566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crb)); 222391689abSStefano Zampini /* this is not null only if the smoother on the finest level 223391689abSStefano Zampini changes the rhs during PreSolve */ 2249566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->b)); 2259566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[n - 1]->B)); 2263aeaf226SBarry Smith 2273aeaf226SBarry Smith for (i = 0; i < n; i++) { 2282b3cbbdaSStefano Zampini PetscCall(MatDestroy(&mglevels[i]->coarseSpace)); 2299566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->A)); 23048a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd)); 2319566063dSJacob Faibussowitsch PetscCall(KSPReset(mglevels[i]->smoothu)); 2329566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr)); 2333aeaf226SBarry Smith } 234f3b08a26SMatthew G. Knepley mg->Nc = 0; 2353aeaf226SBarry Smith } 2363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2373aeaf226SBarry Smith } 2383aeaf226SBarry Smith 23941b6fd38SMatthew G. Knepley /* Implementing CR 24041b6fd38SMatthew G. Knepley 24141b6fd38SMatthew 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 24241b6fd38SMatthew G. Knepley 24341b6fd38SMatthew G. Knepley Inj^T (Inj Inj^T)^{-1} Inj 24441b6fd38SMatthew G. Knepley 24541b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have 24641b6fd38SMatthew G. Knepley 24741b6fd38SMatthew G. Knepley Inj^T Inj 24841b6fd38SMatthew G. Knepley 24941b6fd38SMatthew G. Knepley and 25041b6fd38SMatthew G. Knepley 25141b6fd38SMatthew G. Knepley S = I - Inj^T Inj 25241b6fd38SMatthew G. Knepley 25341b6fd38SMatthew G. Knepley since 25441b6fd38SMatthew G. Knepley 25541b6fd38SMatthew G. Knepley Inj S = Inj - (Inj Inj^T) Inj = 0. 25641b6fd38SMatthew G. Knepley 25741b6fd38SMatthew G. Knepley Brannick suggests 25841b6fd38SMatthew G. Knepley 25941b6fd38SMatthew G. Knepley A \to S^T A S \qquad\mathrm{and}\qquad M \to S^T M S 26041b6fd38SMatthew G. Knepley 26141b6fd38SMatthew 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 26241b6fd38SMatthew G. Knepley 26341b6fd38SMatthew G. Knepley M^{-1} A \to S M^{-1} A S 26441b6fd38SMatthew G. Knepley 26541b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left. 26641b6fd38SMatthew G. Knepley 26741b6fd38SMatthew G. Knepley Check: || Inj P - I ||_F < tol 26841b6fd38SMatthew G. Knepley Check: In general, Inj Inj^T = I 26941b6fd38SMatthew G. Knepley */ 27041b6fd38SMatthew G. Knepley 27141b6fd38SMatthew G. Knepley typedef struct { 27241b6fd38SMatthew G. Knepley PC mg; /* The PCMG object */ 27341b6fd38SMatthew G. Knepley PetscInt l; /* The multigrid level for this solver */ 27441b6fd38SMatthew G. Knepley Mat Inj; /* The injection matrix */ 27541b6fd38SMatthew G. Knepley Mat S; /* I - Inj^T Inj */ 27641b6fd38SMatthew G. Knepley } CRContext; 27741b6fd38SMatthew G. Knepley 278d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc) 279d71ae5a4SJacob Faibussowitsch { 28041b6fd38SMatthew G. Knepley CRContext *ctx; 28141b6fd38SMatthew G. Knepley Mat It; 28241b6fd38SMatthew G. Knepley 28341b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2849566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 2859566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It)); 28628b400f6SJacob Faibussowitsch PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG"); 2879566063dSJacob Faibussowitsch PetscCall(MatCreateTranspose(It, &ctx->Inj)); 2889566063dSJacob Faibussowitsch PetscCall(MatCreateNormal(ctx->Inj, &ctx->S)); 2899566063dSJacob Faibussowitsch PetscCall(MatScale(ctx->S, -1.0)); 2909566063dSJacob Faibussowitsch PetscCall(MatShift(ctx->S, 1.0)); 2913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 29241b6fd38SMatthew G. Knepley } 29341b6fd38SMatthew G. Knepley 294d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y) 295d71ae5a4SJacob Faibussowitsch { 29641b6fd38SMatthew G. Knepley CRContext *ctx; 29741b6fd38SMatthew G. Knepley 29841b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 2999566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 3009566063dSJacob Faibussowitsch PetscCall(MatMult(ctx->S, x, y)); 3013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30241b6fd38SMatthew G. Knepley } 30341b6fd38SMatthew G. Knepley 304d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc) 305d71ae5a4SJacob Faibussowitsch { 30641b6fd38SMatthew G. Knepley CRContext *ctx; 30741b6fd38SMatthew G. Knepley 30841b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3099566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx)); 3109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->Inj)); 3119566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->S)); 3129566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 3139566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(pc, NULL)); 3143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 31541b6fd38SMatthew G. Knepley } 31641b6fd38SMatthew G. Knepley 317d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr) 318d71ae5a4SJacob Faibussowitsch { 31941b6fd38SMatthew G. Knepley CRContext *ctx; 32041b6fd38SMatthew G. Knepley 32141b6fd38SMatthew G. Knepley PetscFunctionBeginUser; 3229566063dSJacob Faibussowitsch PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr)); 3239566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)")); 3249566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(1, &ctx)); 32541b6fd38SMatthew G. Knepley ctx->mg = pc; 32641b6fd38SMatthew G. Knepley ctx->l = l; 3279566063dSJacob Faibussowitsch PetscCall(PCSetType(*cr, PCSHELL)); 3289566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(*cr, ctx)); 3299566063dSJacob Faibussowitsch PetscCall(PCShellSetApply(*cr, CRApply_Private)); 3309566063dSJacob Faibussowitsch PetscCall(PCShellSetSetUp(*cr, CRSetup_Private)); 3319566063dSJacob Faibussowitsch PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private)); 3323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33341b6fd38SMatthew G. Knepley } 33441b6fd38SMatthew G. Knepley 3358f4fb22eSMark Adams PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *); 3368f4fb22eSMark Adams 337d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms) 338d71ae5a4SJacob Faibussowitsch { 339f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 340ce94432eSBarry Smith MPI_Comm comm; 3413aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels; 34210eca3edSLisandro Dalcin PCMGType mgtype = mg->am; 34310167fecSBarry Smith PetscInt mgctype = (PetscInt)PC_MG_CYCLE_V; 344f3fbd535SBarry Smith PetscInt i; 345f3fbd535SBarry Smith PetscMPIInt size; 346f3fbd535SBarry Smith const char *prefix; 347f3fbd535SBarry Smith PC ipc; 3483aeaf226SBarry Smith PetscInt n; 3494b9ad928SBarry Smith 3504b9ad928SBarry Smith PetscFunctionBegin; 3510700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 352548767e0SJed Brown PetscValidLogicalCollectiveInt(pc, levels, 2); 3533ba16761SJacob Faibussowitsch if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS); 3549566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 3553aeaf226SBarry Smith if (mglevels) { 35610eca3edSLisandro Dalcin mgctype = mglevels[0]->cycles; 3573aeaf226SBarry Smith /* changing the number of levels so free up the previous stuff */ 3589566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 3593aeaf226SBarry Smith n = mglevels[0]->levels; 3603aeaf226SBarry Smith for (i = 0; i < n; i++) { 36148a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 3629566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 3639566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 3649566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 3653aeaf226SBarry Smith } 3669566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 3673aeaf226SBarry Smith } 368f3fbd535SBarry Smith 369f3fbd535SBarry Smith mg->nlevels = levels; 370f3fbd535SBarry Smith 3719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(levels, &mglevels)); 372f3fbd535SBarry Smith 3739566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 374f3fbd535SBarry Smith 375a9db87a2SMatthew G Knepley mg->stageApply = 0; 376f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 3774dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mglevels[i])); 3782fa5cd67SKarl Rupp 379f3fbd535SBarry Smith mglevels[i]->level = i; 380f3fbd535SBarry Smith mglevels[i]->levels = levels; 38110eca3edSLisandro Dalcin mglevels[i]->cycles = mgctype; 382336babb1SJed Brown mg->default_smoothu = 2; 383336babb1SJed Brown mg->default_smoothd = 2; 38463e6d426SJed Brown mglevels[i]->eventsmoothsetup = 0; 38563e6d426SJed Brown mglevels[i]->eventsmoothsolve = 0; 38663e6d426SJed Brown mglevels[i]->eventresidual = 0; 38763e6d426SJed Brown mglevels[i]->eventinterprestrict = 0; 388f3fbd535SBarry Smith 389f3fbd535SBarry Smith if (comms) comm = comms[i]; 390d5a8f7e6SBarry Smith if (comm != MPI_COMM_NULL) { 3919566063dSJacob Faibussowitsch PetscCall(KSPCreate(comm, &mglevels[i]->smoothd)); 3923821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel)); 3939566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure)); 3949566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i)); 3959566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix)); 3969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level)); 3978f4fb22eSMark Adams if (i == 0 && levels > 1) { // coarse grid 3989566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_")); 399f3fbd535SBarry Smith 4009dbfc187SHong Zhang /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 4019566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY)); 4029566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc)); 4039566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 404f3fbd535SBarry Smith if (size > 1) { 4059566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCREDUNDANT)); 406f3fbd535SBarry Smith } else { 4079566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCLU)); 408f3fbd535SBarry Smith } 4099566063dSJacob Faibussowitsch PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS)); 4108f4fb22eSMark Adams } else { 4118f4fb22eSMark Adams char tprefix[128]; 4128f4fb22eSMark Adams 4138f4fb22eSMark Adams PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV)); 4148f4fb22eSMark Adams PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL)); 4158f4fb22eSMark Adams PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE)); 4168f4fb22eSMark Adams PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc)); 4178f4fb22eSMark Adams PetscCall(PCSetType(ipc, PCSOR)); 418fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd)); 4198f4fb22eSMark Adams 4208f4fb22eSMark Adams if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_' 4218f4fb22eSMark Adams PetscBool set; 4228f4fb22eSMark Adams PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set)); 4238f4fb22eSMark Adams if (set) { 4248f4fb22eSMark Adams if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix)); 4258f4fb22eSMark Adams else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_")); 4268f4fb22eSMark Adams PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix)); 4278f4fb22eSMark Adams } else { 428835f2295SStefano Zampini PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i)); 4298f4fb22eSMark Adams PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 4308f4fb22eSMark Adams } 4318f4fb22eSMark Adams } else { 432835f2295SStefano Zampini PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i)); 4338f4fb22eSMark Adams PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 4348f4fb22eSMark Adams } 435f3fbd535SBarry Smith } 436d5a8f7e6SBarry Smith } 437f3fbd535SBarry Smith mglevels[i]->smoothu = mglevels[i]->smoothd; 43831567311SBarry Smith mg->rtol = 0.0; 43931567311SBarry Smith mg->abstol = 0.0; 44031567311SBarry Smith mg->dtol = 0.0; 44131567311SBarry Smith mg->ttol = 0.0; 44231567311SBarry Smith mg->cyclesperpcapply = 1; 443f3fbd535SBarry Smith } 444f3fbd535SBarry Smith mg->levels = mglevels; 4459566063dSJacob Faibussowitsch PetscCall(PCMGSetType(pc, mgtype)); 4463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4474b9ad928SBarry Smith } 4484b9ad928SBarry Smith 44997d33e41SMatthew G. Knepley /*@C 450f1580f4eSBarry Smith PCMGSetLevels - Sets the number of levels to use with `PCMG`. 451f1580f4eSBarry Smith Must be called before any other `PCMG` routine. 45297d33e41SMatthew G. Knepley 453c3339decSBarry Smith Logically Collective 45497d33e41SMatthew G. Knepley 45597d33e41SMatthew G. Knepley Input Parameters: 45697d33e41SMatthew G. Knepley + pc - the preconditioner context 45797d33e41SMatthew G. Knepley . levels - the number of levels 45897d33e41SMatthew G. Knepley - comms - optional communicators for each level; this is to allow solving the coarser problems 459d5a8f7e6SBarry Smith on smaller sets of processes. For processes that are not included in the computation 46020f4b53cSBarry Smith you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes 46105552d4bSJunchao Zhang should participate in each level of problem. 46297d33e41SMatthew G. Knepley 46397d33e41SMatthew G. Knepley Level: intermediate 46497d33e41SMatthew G. Knepley 46597d33e41SMatthew G. Knepley Notes: 46620f4b53cSBarry Smith If the number of levels is one then the multigrid uses the `-mg_levels` prefix 4678f4fb22eSMark Adams for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix. 46897d33e41SMatthew G. Knepley 469d5a8f7e6SBarry Smith You can free the information in comms after this routine is called. 470d5a8f7e6SBarry Smith 471f1580f4eSBarry Smith The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level 472d5a8f7e6SBarry Smith are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on 473d5a8f7e6SBarry Smith the two levels, rank 0 in the original communicator will pass in an array of 2 communicators 474d5a8f7e6SBarry Smith of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators 475f1580f4eSBarry Smith the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate 476d5a8f7e6SBarry Smith in the coarse grid solve. 477d5a8f7e6SBarry Smith 478f1580f4eSBarry Smith Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one 479d5a8f7e6SBarry Smith must take special care in providing the restriction and interpolation operation. We recommend 480d5a8f7e6SBarry Smith providing these as two step operations; first perform a standard restriction or interpolation on 481d5a8f7e6SBarry Smith the full number of ranks for that level and then use an MPI call to copy the resulting vector 48205552d4bSJunchao Zhang array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both 483d5a8f7e6SBarry Smith cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and 48420f4b53cSBarry Smith receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries. 485d5a8f7e6SBarry Smith 486feefa0e1SJacob Faibussowitsch Fortran Notes: 48720f4b53cSBarry Smith Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM` 488f1580f4eSBarry Smith is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc. 489d5a8f7e6SBarry Smith 490562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()` 49197d33e41SMatthew G. Knepley @*/ 492d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) 493d71ae5a4SJacob Faibussowitsch { 49497d33e41SMatthew G. Knepley PetscFunctionBegin; 49597d33e41SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 4964f572ea9SToby Isaac if (comms) PetscAssertPointer(comms, 3); 497cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms)); 4983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 49997d33e41SMatthew G. Knepley } 50097d33e41SMatthew G. Knepley 501d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc) 502d71ae5a4SJacob Faibussowitsch { 503a06653b4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 504a06653b4SBarry Smith PC_MG_Levels **mglevels = mg->levels; 505a06653b4SBarry Smith PetscInt i, n; 506c07bf074SBarry Smith 507c07bf074SBarry Smith PetscFunctionBegin; 5089566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 509a06653b4SBarry Smith if (mglevels) { 510a06653b4SBarry Smith n = mglevels[0]->levels; 511a06653b4SBarry Smith for (i = 0; i < n; i++) { 51248a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 5139566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 5149566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 5159566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 516a06653b4SBarry Smith } 5179566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 518a06653b4SBarry Smith } 5199566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 5209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5222b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL)); 5232b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL)); 5242b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL)); 5252b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5262b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5272b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL)); 5282b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL)); 5292b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL)); 5302b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL)); 5312b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL)); 5322b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL)); 5333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 534f3fbd535SBarry Smith } 535f3fbd535SBarry Smith 536f3fbd535SBarry Smith /* 537f3fbd535SBarry Smith PCApply_MG - Runs either an additive, multiplicative, Kaskadic 538f3fbd535SBarry Smith or full cycle of multigrid. 539f3fbd535SBarry Smith 540f3fbd535SBarry Smith Note: 541f3fbd535SBarry Smith A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 542f3fbd535SBarry Smith */ 543d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) 544d71ae5a4SJacob Faibussowitsch { 545f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 546f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 547391689abSStefano Zampini PC tpc; 548f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 54930b0564aSStefano Zampini PetscBool changeu, changed, matapp; 550f3fbd535SBarry Smith 551f3fbd535SBarry Smith PetscFunctionBegin; 55230b0564aSStefano Zampini matapp = (PetscBool)(B && X); 5539566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply)); 554e1d8e5deSBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 555298cc208SBarry Smith for (i = 0; i < levels; i++) { 556e1d8e5deSBarry Smith if (!mglevels[i]->A) { 5579566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 5589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 559e1d8e5deSBarry Smith } 560e1d8e5deSBarry Smith } 561e1d8e5deSBarry Smith 5629566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 5639566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 5649566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 5659566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 566391689abSStefano Zampini if (!changeu && !changed) { 56730b0564aSStefano Zampini if (matapp) { 5689566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 56930b0564aSStefano Zampini mglevels[levels - 1]->B = B; 57030b0564aSStefano Zampini } else { 5719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 572f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 57330b0564aSStefano Zampini } 574391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 57530b0564aSStefano Zampini if (matapp) { 57630b0564aSStefano Zampini if (mglevels[levels - 1]->B) { 57730b0564aSStefano Zampini PetscInt N1, N2; 57830b0564aSStefano Zampini PetscBool flg; 57930b0564aSStefano Zampini 5809566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1)); 5819566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N2)); 5829566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg)); 58348a46eb9SPierre Jolivet if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 58430b0564aSStefano Zampini } 58530b0564aSStefano Zampini if (!mglevels[levels - 1]->B) { 5869566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B)); 58730b0564aSStefano Zampini } else { 5889566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN)); 58930b0564aSStefano Zampini } 59030b0564aSStefano Zampini } else { 591391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 592391689abSStefano Zampini Vec *vec; 593391689abSStefano Zampini 5949566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 595391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 5969566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 597391689abSStefano Zampini } 5989566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 599391689abSStefano Zampini } 60030b0564aSStefano Zampini } 6019371c9d4SSatish Balay if (matapp) { 6029371c9d4SSatish Balay mglevels[levels - 1]->X = X; 6039371c9d4SSatish Balay } else { 6049371c9d4SSatish Balay mglevels[levels - 1]->x = x; 6059371c9d4SSatish Balay } 60630b0564aSStefano Zampini 60730b0564aSStefano Zampini /* If coarser Xs are present, it means we have already block applied the PC at least once 60830b0564aSStefano Zampini Reset operators if sizes/type do no match */ 60930b0564aSStefano Zampini if (matapp && levels > 1 && mglevels[levels - 2]->X) { 61030b0564aSStefano Zampini PetscInt Xc, Bc; 61130b0564aSStefano Zampini PetscBool flg; 61230b0564aSStefano Zampini 6139566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc)); 6149566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc)); 6159566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg)); 61630b0564aSStefano Zampini if (Xc != Bc || !flg) { 6179566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->R)); 61830b0564aSStefano Zampini for (i = 0; i < levels - 1; i++) { 6199566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->R)); 6209566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 6219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 62230b0564aSStefano Zampini } 62330b0564aSStefano Zampini } 62430b0564aSStefano Zampini } 625391689abSStefano Zampini 62631567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6279566063dSJacob Faibussowitsch if (matapp) PetscCall(MatZeroEntries(X)); 6289566063dSJacob Faibussowitsch else PetscCall(VecZeroEntries(x)); 62948a46eb9SPierre Jolivet for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL)); 6302fa5cd67SKarl Rupp } else if (mg->am == PC_MG_ADDITIVE) { 6319566063dSJacob Faibussowitsch PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp)); 6322fa5cd67SKarl Rupp } else if (mg->am == PC_MG_KASKADE) { 6339566063dSJacob Faibussowitsch PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp)); 6342fa5cd67SKarl Rupp } else { 6359566063dSJacob Faibussowitsch PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp)); 636f3fbd535SBarry Smith } 6379566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePop()); 63830b0564aSStefano Zampini if (!changeu && !changed) { 6399371c9d4SSatish Balay if (matapp) { 6409371c9d4SSatish Balay mglevels[levels - 1]->B = NULL; 6419371c9d4SSatish Balay } else { 6429371c9d4SSatish Balay mglevels[levels - 1]->b = NULL; 6439371c9d4SSatish Balay } 64430b0564aSStefano Zampini } 6453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 646f3fbd535SBarry Smith } 647f3fbd535SBarry Smith 648d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) 649d71ae5a4SJacob Faibussowitsch { 650fcb023d4SJed Brown PetscFunctionBegin; 6519566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE)); 6523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 653fcb023d4SJed Brown } 654fcb023d4SJed Brown 655d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) 656d71ae5a4SJacob Faibussowitsch { 657fcb023d4SJed Brown PetscFunctionBegin; 6589566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE)); 6593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66030b0564aSStefano Zampini } 66130b0564aSStefano Zampini 662d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) 663d71ae5a4SJacob Faibussowitsch { 66430b0564aSStefano Zampini PetscFunctionBegin; 6659566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE)); 6663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 667fcb023d4SJed Brown } 668f3fbd535SBarry Smith 6694dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x) 6704dbf25a8SPierre Jolivet { 6714dbf25a8SPierre Jolivet PetscFunctionBegin; 6724dbf25a8SPierre Jolivet PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE)); 6734dbf25a8SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 6744dbf25a8SPierre Jolivet } 6754dbf25a8SPierre Jolivet 676ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject) 677d71ae5a4SJacob Faibussowitsch { 678710315b6SLawrence Mitchell PetscInt levels, cycles; 679f3b08a26SMatthew G. Knepley PetscBool flg, flg2; 680f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 6813d3eaba7SBarry Smith PC_MG_Levels **mglevels; 682f3fbd535SBarry Smith PCMGType mgtype; 683f3fbd535SBarry Smith PCMGCycleType mgctype; 6842134b1e4SBarry Smith PCMGGalerkinType gtype; 6852b3cbbdaSStefano Zampini PCMGCoarseSpaceType coarseSpaceType; 686f3fbd535SBarry Smith 687f3fbd535SBarry Smith PetscFunctionBegin; 6881d743356SStefano Zampini levels = PetscMax(mg->nlevels, 1); 689d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options"); 6909566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg)); 6911a97d7b6SStefano Zampini if (!flg && !mg->levels && pc->dm) { 6929566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 693eb3f98d2SBarry Smith levels++; 6943aeaf226SBarry Smith mg->usedmfornumberoflevels = PETSC_TRUE; 695eb3f98d2SBarry Smith } 6969566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 6973aeaf226SBarry Smith mglevels = mg->levels; 6983aeaf226SBarry Smith 699f3fbd535SBarry Smith mgctype = (PCMGCycleType)mglevels[0]->cycles; 7009566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg)); 7011baa6e33SBarry Smith if (flg) PetscCall(PCMGSetCycleType(pc, mgctype)); 7022b3cbbdaSStefano Zampini coarseSpaceType = mg->coarseSpaceType; 7032b3cbbdaSStefano 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)); 7042b3cbbdaSStefano Zampini if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType)); 7059566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg)); 7069566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg)); 70741b6fd38SMatthew G. Knepley flg2 = PETSC_FALSE; 7089566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg)); 7099566063dSJacob Faibussowitsch if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2)); 710f56b1265SBarry Smith flg = PETSC_FALSE; 7119566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL)); 7121baa6e33SBarry Smith if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc)); 7135544a5bcSStefano Zampini PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)>ype, &flg)); 7145544a5bcSStefano Zampini if (flg) PetscCall(PCMGSetGalerkin(pc, gtype)); 71531567311SBarry Smith mgtype = mg->am; 7169566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg)); 7171baa6e33SBarry Smith if (flg) PetscCall(PCMGSetType(pc, mgtype)); 71831567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 7199566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg)); 7201baa6e33SBarry Smith if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles)); 721f3fbd535SBarry Smith } 722f3fbd535SBarry Smith flg = PETSC_FALSE; 7239566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL)); 724f3fbd535SBarry Smith if (flg) { 725f3fbd535SBarry Smith PetscInt i; 726f3fbd535SBarry Smith char eventname[128]; 7271a97d7b6SStefano Zampini 728f3fbd535SBarry Smith levels = mglevels[0]->levels; 729f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 730835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i)); 7319566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup)); 732835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i)); 7339566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve)); 734f3fbd535SBarry Smith if (i) { 735835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i)); 7369566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual)); 737835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i)); 7389566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict)); 739f3fbd535SBarry Smith } 740f3fbd535SBarry Smith } 741eec35531SMatthew G Knepley 7422611ad71SToby Isaac if (PetscDefined(USE_LOG)) { 7432611ad71SToby Isaac const char sname[] = "MG Apply"; 744eec35531SMatthew G Knepley 7452611ad71SToby Isaac PetscCall(PetscLogStageGetId(sname, &mg->stageApply)); 7462611ad71SToby Isaac if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply)); 747eec35531SMatthew G Knepley } 748f3fbd535SBarry Smith } 749d0609cedSBarry Smith PetscOptionsHeadEnd(); 750f3b08a26SMatthew G. Knepley /* Check option consistency */ 7519566063dSJacob Faibussowitsch PetscCall(PCMGGetGalerkin(pc, >ype)); 7529566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptInterpolation(pc, &flg)); 75308401ef6SPierre Jolivet PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator"); 7543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 755f3fbd535SBarry Smith } 756f3fbd535SBarry Smith 7570a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL}; 7580a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL}; 7590a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL}; 7602b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL}; 761f3fbd535SBarry Smith 7629804daf3SBarry Smith #include <petscdraw.h> 763d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) 764d71ae5a4SJacob Faibussowitsch { 765f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 766f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 767e3deeeafSJed Brown PetscInt levels = mglevels ? mglevels[0]->levels : 0, i; 768219b1045SBarry Smith PetscBool iascii, isbinary, isdraw; 769f3fbd535SBarry Smith 770f3fbd535SBarry Smith PetscFunctionBegin; 7719566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 7729566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 7739566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 774f3fbd535SBarry Smith if (iascii) { 775e3deeeafSJed Brown const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 77663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename)); 77748a46eb9SPierre Jolivet if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply)); 7782134b1e4SBarry Smith if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 7799566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n")); 7802134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 7819566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n")); 7822134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 7839566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n")); 7842134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 7859566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n")); 7864f66f45eSBarry Smith } else { 7879566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n")); 788f3fbd535SBarry Smith } 7891baa6e33SBarry Smith if (mg->view) PetscCall((*mg->view)(pc, viewer)); 790f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 79163a3b9bcSJacob Faibussowitsch if (i) { 79263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 793f3fbd535SBarry Smith } else { 79463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 795f3fbd535SBarry Smith } 7969566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 7979566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 7989566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 799f3fbd535SBarry Smith if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 8009566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n")); 801f3fbd535SBarry Smith } else if (i) { 80263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 8039566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8049566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8059566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 806f3fbd535SBarry Smith } 80741b6fd38SMatthew G. Knepley if (i && mglevels[i]->cr) { 80863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i)); 8099566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8109566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->cr, viewer)); 8119566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 81241b6fd38SMatthew G. Knepley } 813f3fbd535SBarry Smith } 8145b0b0462SBarry Smith } else if (isbinary) { 8155b0b0462SBarry Smith for (i = levels - 1; i >= 0; i--) { 8169566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 81748a46eb9SPierre Jolivet if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8185b0b0462SBarry Smith } 819219b1045SBarry Smith } else if (isdraw) { 820219b1045SBarry Smith PetscDraw draw; 821b4375e8dSPeter Brune PetscReal x, w, y, bottom, th; 8229566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 8239566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 8249566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, NULL, &th)); 825219b1045SBarry Smith bottom = y - th; 826219b1045SBarry Smith for (i = levels - 1; i >= 0; i--) { 827b4375e8dSPeter Brune if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 8289566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 8299566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8309566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 831b4375e8dSPeter Brune } else { 832b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x); 8339566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 8349566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8359566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 8369566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 8379566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8389566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 839b4375e8dSPeter Brune } 8409566063dSJacob Faibussowitsch PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL)); 8411cd381d6SBarry Smith bottom -= th; 842219b1045SBarry Smith } 8435b0b0462SBarry Smith } 8443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 845f3fbd535SBarry Smith } 846f3fbd535SBarry Smith 847af0996ceSBarry Smith #include <petsc/private/kspimpl.h> 848cab2e9ccSBarry Smith 849f3fbd535SBarry Smith /* 850f3fbd535SBarry Smith Calls setup for the KSP on each level 851f3fbd535SBarry Smith */ 852d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc) 853d71ae5a4SJacob Faibussowitsch { 854f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 855f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 8561a97d7b6SStefano Zampini PetscInt i, n; 85798e04984SBarry Smith PC cpc; 8583db492dfSBarry Smith PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE; 859f3fbd535SBarry Smith Mat dA, dB; 860f3fbd535SBarry Smith Vec tvec; 861218a07d4SBarry Smith DM *dms; 8620a545947SLisandro Dalcin PetscViewer viewer = NULL; 86341b6fd38SMatthew G. Knepley PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE; 8642b3cbbdaSStefano Zampini PetscBool adaptInterpolation = mg->adaptInterpolation; 865f3fbd535SBarry Smith 866f3fbd535SBarry Smith PetscFunctionBegin; 86728b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up"); 8681a97d7b6SStefano Zampini n = mglevels[0]->levels; 86901bc414fSDmitry Karpeev /* FIX: Move this to PCSetFromOptions_MG? */ 8703aeaf226SBarry Smith if (mg->usedmfornumberoflevels) { 8713aeaf226SBarry Smith PetscInt levels; 8729566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 8733aeaf226SBarry Smith levels++; 8743aeaf226SBarry Smith if (levels > n) { /* the problem is now being solved on a finer grid */ 8759566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 8763aeaf226SBarry Smith n = levels; 8779566063dSJacob Faibussowitsch PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 8783aeaf226SBarry Smith mglevels = mg->levels; 8793aeaf226SBarry Smith } 8803aeaf226SBarry Smith } 8819566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc)); 8823aeaf226SBarry Smith 883f3fbd535SBarry Smith /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 884f3fbd535SBarry Smith /* so use those from global PC */ 885f3fbd535SBarry Smith /* Is this what we always want? What if user wants to keep old one? */ 8869566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset)); 88798e04984SBarry Smith if (opsset) { 88898e04984SBarry Smith Mat mmat; 8899566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat)); 89098e04984SBarry Smith if (mmat == pc->pmat) opsset = PETSC_FALSE; 89198e04984SBarry Smith } 8924a5f07a5SMark F. Adams 89341b6fd38SMatthew G. Knepley /* Create CR solvers */ 8949566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptCR(pc, &doCR)); 89541b6fd38SMatthew G. Knepley if (doCR) { 89641b6fd38SMatthew G. Knepley const char *prefix; 89741b6fd38SMatthew G. Knepley 8989566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 89941b6fd38SMatthew G. Knepley for (i = 1; i < n; ++i) { 90041b6fd38SMatthew G. Knepley PC ipc, cr; 90141b6fd38SMatthew G. Knepley char crprefix[128]; 90241b6fd38SMatthew G. Knepley 9039566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr)); 9043821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel)); 9059566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 9069566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i)); 9079566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 9089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 9099566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 9109566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 9119566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 9129566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->cr, &ipc)); 91341b6fd38SMatthew G. Knepley 9149566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCCOMPOSITE)); 9159566063dSJacob Faibussowitsch PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 9169566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPCType(ipc, PCSOR)); 9179566063dSJacob Faibussowitsch PetscCall(CreateCR_Private(pc, i, &cr)); 9189566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPC(ipc, cr)); 9199566063dSJacob Faibussowitsch PetscCall(PCDestroy(&cr)); 92041b6fd38SMatthew G. Knepley 921fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd)); 9229566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 923835f2295SStefano Zampini PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i)); 9249566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 92541b6fd38SMatthew G. Knepley } 92641b6fd38SMatthew G. Knepley } 92741b6fd38SMatthew G. Knepley 9284a5f07a5SMark F. Adams if (!opsset) { 9299566063dSJacob Faibussowitsch PetscCall(PCGetUseAmat(pc, &use_amat)); 9304a5f07a5SMark F. Adams if (use_amat) { 9319566063dSJacob 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")); 9329566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat)); 93369858f1bSStefano Zampini } else { 9349566063dSJacob 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")); 9359566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat)); 9364a5f07a5SMark F. Adams } 9374a5f07a5SMark F. Adams } 938f3fbd535SBarry Smith 9399c7ffb39SBarry Smith for (i = n - 1; i > 0; i--) { 9409c7ffb39SBarry Smith if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 9419c7ffb39SBarry Smith missinginterpolate = PETSC_TRUE; 9422b3cbbdaSStefano Zampini break; 9439c7ffb39SBarry Smith } 9449c7ffb39SBarry Smith } 9452134b1e4SBarry Smith 9469566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB)); 9472134b1e4SBarry Smith if (dA == dB) dAeqdB = PETSC_TRUE; 9482b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) { 9492134b1e4SBarry Smith needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */ 9502134b1e4SBarry Smith } 9512134b1e4SBarry Smith 9522b3cbbdaSStefano Zampini if (pc->dm && !pc->setupcalled) { 9532b3cbbdaSStefano Zampini /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 9542b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm)); 9552b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE)); 9562b3cbbdaSStefano Zampini if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) { 9572b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm)); 9582b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE)); 9592b3cbbdaSStefano Zampini } 9602b3cbbdaSStefano Zampini if (mglevels[n - 1]->cr) { 9612b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm)); 9622b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE)); 9632b3cbbdaSStefano Zampini } 9642b3cbbdaSStefano Zampini } 9652b3cbbdaSStefano Zampini 9669c7ffb39SBarry Smith /* 9679c7ffb39SBarry Smith Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 9682b3cbbdaSStefano Zampini Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 9699c7ffb39SBarry Smith */ 97032fe681dSStefano Zampini if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 97132fe681dSStefano Zampini /* first see if we can compute a coarse space */ 97232fe681dSStefano Zampini if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) { 97332fe681dSStefano Zampini for (i = n - 2; i > -1; i--) { 97432fe681dSStefano Zampini if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) { 97532fe681dSStefano Zampini PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace)); 97632fe681dSStefano Zampini PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace)); 97732fe681dSStefano Zampini } 97832fe681dSStefano Zampini } 97932fe681dSStefano Zampini } else { /* construct the interpolation from the DMs */ 9802e499ae9SBarry Smith Mat p; 98173250ac0SBarry Smith Vec rscale; 9829566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &dms)); 983218a07d4SBarry Smith dms[n - 1] = pc->dm; 984ef1267afSMatthew G. Knepley /* Separately create them so we do not get DMKSP interference between levels */ 9859566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i])); 986218a07d4SBarry Smith for (i = n - 2; i > -1; i--) { 987942e3340SBarry Smith DMKSP kdm; 988eab52d2bSLawrence Mitchell PetscBool dmhasrestrict, dmhasinject; 9899566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i])); 9909566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE)); 991c27ee7a3SPatrick Farrell if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 9929566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i])); 9939566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE)); 994c27ee7a3SPatrick Farrell } 99541b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 9969566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->cr, dms[i])); 9979566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE)); 99841b6fd38SMatthew G. Knepley } 9999566063dSJacob Faibussowitsch PetscCall(DMGetDMKSPWrite(dms[i], &kdm)); 1000d1a3e677SJed Brown /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 1001d1a3e677SJed Brown * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 10020298fd71SBarry Smith kdm->ops->computerhs = NULL; 10030298fd71SBarry Smith kdm->rhsctx = NULL; 100424c3aa18SBarry Smith if (!mglevels[i + 1]->interpolate) { 10059566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale)); 10069566063dSJacob Faibussowitsch PetscCall(PCMGSetInterpolation(pc, i + 1, p)); 10079566063dSJacob Faibussowitsch if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale)); 10089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rscale)); 10099566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 1010218a07d4SBarry Smith } 10119566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict)); 10123ad4599aSBarry Smith if (dmhasrestrict && !mglevels[i + 1]->restrct) { 10139566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p)); 10149566063dSJacob Faibussowitsch PetscCall(PCMGSetRestriction(pc, i + 1, p)); 10159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 10163ad4599aSBarry Smith } 10179566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(dms[i], &dmhasinject)); 1018eab52d2bSLawrence Mitchell if (dmhasinject && !mglevels[i + 1]->inject) { 10199566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p)); 10209566063dSJacob Faibussowitsch PetscCall(PCMGSetInjection(pc, i + 1, p)); 10219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 1022eab52d2bSLawrence Mitchell } 102324c3aa18SBarry Smith } 10242d2b81a6SBarry Smith 10259566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i])); 10269566063dSJacob Faibussowitsch PetscCall(PetscFree(dms)); 1027ce4cda84SJed Brown } 102832fe681dSStefano Zampini } 1029cab2e9ccSBarry Smith 10302134b1e4SBarry Smith if (mg->galerkin < PC_MG_GALERKIN_NONE) { 10312134b1e4SBarry Smith Mat A, B; 10322134b1e4SBarry Smith PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE; 10332134b1e4SBarry Smith MatReuse reuse = MAT_INITIAL_MATRIX; 10342134b1e4SBarry Smith 10352b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE; 10362b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE; 10372134b1e4SBarry Smith if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 1038f3fbd535SBarry Smith for (i = n - 2; i > -1; i--) { 10397827d75bSBarry 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"); 104048a46eb9SPierre Jolivet if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct)); 104148a46eb9SPierre Jolivet if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate)); 104248a46eb9SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B)); 104348a46eb9SPierre Jolivet if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A)); 104448a46eb9SPierre Jolivet if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B)); 10452134b1e4SBarry Smith /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 10462134b1e4SBarry Smith if (!doA && dAeqdB) { 10479566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B)); 10482134b1e4SBarry Smith A = B; 10492134b1e4SBarry Smith } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 10509566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL)); 10519566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 1052b9367914SBarry Smith } 10532134b1e4SBarry Smith if (!doB && dAeqdB) { 10549566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A)); 10552134b1e4SBarry Smith B = A; 10562134b1e4SBarry Smith } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 10579566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B)); 10589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 10597d537d92SJed Brown } 10602134b1e4SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 10619566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B)); 10629566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)A)); 10639566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)B)); 10642134b1e4SBarry Smith } 10652134b1e4SBarry Smith dA = A; 1066f3fbd535SBarry Smith dB = B; 1067f3fbd535SBarry Smith } 1068f3fbd535SBarry Smith } 1069f3b08a26SMatthew G. Knepley 1070f3b08a26SMatthew G. Knepley /* Adapt interpolation matrices */ 10712b3cbbdaSStefano Zampini if (adaptInterpolation) { 1072f3b08a26SMatthew G. Knepley for (i = 0; i < n; ++i) { 107348a46eb9SPierre Jolivet if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace)); 10742b3cbbdaSStefano Zampini if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace)); 1075f3b08a26SMatthew G. Knepley } 107648a46eb9SPierre Jolivet for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i)); 1077f3b08a26SMatthew G. Knepley } 1078f3b08a26SMatthew G. Knepley 10792134b1e4SBarry Smith if (needRestricts && pc->dm) { 1080caa4e7f2SJed Brown for (i = n - 2; i >= 0; i--) { 1081ccceb50cSJed Brown DM dmfine, dmcoarse; 1082caa4e7f2SJed Brown Mat Restrict, Inject; 1083caa4e7f2SJed Brown Vec rscale; 10849566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine)); 10859566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse)); 10869566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict)); 10879566063dSJacob Faibussowitsch PetscCall(PCMGGetRScale(pc, i + 1, &rscale)); 10889566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(pc, i + 1, &Inject)); 10899566063dSJacob Faibussowitsch PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse)); 1090caa4e7f2SJed Brown } 1091caa4e7f2SJed Brown } 1092f3fbd535SBarry Smith 1093f3fbd535SBarry Smith if (!pc->setupcalled) { 109448a46eb9SPierre Jolivet for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd)); 1095f3fbd535SBarry Smith for (i = 1; i < n; i++) { 109648a46eb9SPierre Jolivet if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu)); 109748a46eb9SPierre Jolivet if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr)); 1098f3fbd535SBarry Smith } 109915229ffcSPierre Jolivet /* insure that if either interpolation or restriction is set the other one is set */ 1100f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11019566063dSJacob Faibussowitsch PetscCall(PCMGGetInterpolation(pc, i, NULL)); 11029566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i, NULL)); 1103f3fbd535SBarry Smith } 1104f3fbd535SBarry Smith for (i = 0; i < n - 1; i++) { 1105f3fbd535SBarry Smith if (!mglevels[i]->b) { 1106f3fbd535SBarry Smith Vec *vec; 11079566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL)); 11089566063dSJacob Faibussowitsch PetscCall(PCMGSetRhs(pc, i, *vec)); 11099566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11109566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1111f3fbd535SBarry Smith } 1112f3fbd535SBarry Smith if (!mglevels[i]->r && i) { 11139566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 11149566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, i, tvec)); 11159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1116f3fbd535SBarry Smith } 1117f3fbd535SBarry Smith if (!mglevels[i]->x) { 11189566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 11199566063dSJacob Faibussowitsch PetscCall(PCMGSetX(pc, i, tvec)); 11209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1121f3fbd535SBarry Smith } 112241b6fd38SMatthew G. Knepley if (doCR) { 11239566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx)); 11249566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb)); 11259566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[i]->crb)); 112641b6fd38SMatthew G. Knepley } 1127f3fbd535SBarry Smith } 1128f3fbd535SBarry Smith if (n != 1 && !mglevels[n - 1]->r) { 1129f3fbd535SBarry Smith /* PCMGSetR() on the finest level if user did not supply it */ 1130f3fbd535SBarry Smith Vec *vec; 11319566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL)); 11329566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, n - 1, *vec)); 11339566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11349566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1135f3fbd535SBarry Smith } 113641b6fd38SMatthew G. Knepley if (doCR) { 11379566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx)); 11389566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb)); 11399566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[n - 1]->crb)); 114041b6fd38SMatthew G. Knepley } 1141f3fbd535SBarry Smith } 1142f3fbd535SBarry Smith 114398e04984SBarry Smith if (pc->dm) { 114498e04984SBarry Smith /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 114598e04984SBarry Smith for (i = 0; i < n - 1; i++) { 114698e04984SBarry Smith if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 114798e04984SBarry Smith } 114898e04984SBarry Smith } 114908549ed4SJed Brown // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g., 115008549ed4SJed Brown // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply. 115108549ed4SJed Brown if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1152f3fbd535SBarry Smith 1153f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11542a21e185SBarry Smith if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1155f3fbd535SBarry Smith /* if doing only down then initial guess is zero */ 11569566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1157f3fbd535SBarry Smith } 11589566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11599566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11609566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothd)); 1161d4645a75SStefano Zampini if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 11629566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1163d42688cbSBarry Smith if (!mglevels[i]->residual) { 1164d42688cbSBarry Smith Mat mat; 11659566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11669566063dSJacob Faibussowitsch PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat)); 1167d42688cbSBarry Smith } 1168fcb023d4SJed Brown if (!mglevels[i]->residualtranspose) { 1169fcb023d4SJed Brown Mat mat; 11709566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11719566063dSJacob Faibussowitsch PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat)); 1172fcb023d4SJed Brown } 1173f3fbd535SBarry Smith } 1174f3fbd535SBarry Smith for (i = 1; i < n; i++) { 1175f3fbd535SBarry Smith if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1176f3fbd535SBarry Smith Mat downmat, downpmat; 1177f3fbd535SBarry Smith 1178f3fbd535SBarry Smith /* check if operators have been set for up, if not use down operators to set them */ 11799566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL)); 1180f3fbd535SBarry Smith if (!opsset) { 11819566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11829566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat)); 1183f3fbd535SBarry Smith } 1184f3fbd535SBarry Smith 11859566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE)); 11869566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11879566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothu)); 1188d4645a75SStefano Zampini if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR; 11899566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1190f3fbd535SBarry Smith } 119141b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 119241b6fd38SMatthew G. Knepley Mat downmat, downpmat; 119341b6fd38SMatthew G. Knepley 119441b6fd38SMatthew G. Knepley /* check if operators have been set for up, if not use down operators to set them */ 11959566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL)); 119641b6fd38SMatthew G. Knepley if (!opsset) { 11979566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11989566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat)); 119941b6fd38SMatthew G. Knepley } 120041b6fd38SMatthew G. Knepley 12019566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 12029566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 12039566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->cr)); 1204d4645a75SStefano Zampini if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR; 12059566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 120641b6fd38SMatthew G. Knepley } 1207f3fbd535SBarry Smith } 1208f3fbd535SBarry Smith 12099566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 12109566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[0]->smoothd)); 1211d4645a75SStefano Zampini if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 12129566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1213f3fbd535SBarry Smith 1214f3fbd535SBarry Smith /* 1215f3fbd535SBarry Smith Dump the interpolation/restriction matrices plus the 1216e3c5b3baSBarry Smith Jacobian/stiffness on each level. This allows MATLAB users to 1217f3fbd535SBarry Smith easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1218f3fbd535SBarry Smith 1219f3fbd535SBarry Smith Only support one or the other at the same time. 1220f3fbd535SBarry Smith */ 1221f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER) 12229566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL)); 1223ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1224f3fbd535SBarry Smith dump = PETSC_FALSE; 1225f3fbd535SBarry Smith #endif 12269566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL)); 1227ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1228f3fbd535SBarry Smith 1229f3fbd535SBarry Smith if (viewer) { 123048a46eb9SPierre Jolivet for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer)); 1231f3fbd535SBarry Smith for (i = 0; i < n; i++) { 12329566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc)); 12339566063dSJacob Faibussowitsch PetscCall(MatView(pc->mat, viewer)); 1234f3fbd535SBarry Smith } 1235f3fbd535SBarry Smith } 12363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1237f3fbd535SBarry Smith } 1238f3fbd535SBarry Smith 1239d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 1240d71ae5a4SJacob Faibussowitsch { 124197d33e41SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 124297d33e41SMatthew G. Knepley 124397d33e41SMatthew G. Knepley PetscFunctionBegin; 124497d33e41SMatthew G. Knepley *levels = mg->nlevels; 12453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124697d33e41SMatthew G. Knepley } 124797d33e41SMatthew G. Knepley 12484b9ad928SBarry Smith /*@ 1249f1580f4eSBarry Smith PCMGGetLevels - Gets the number of levels to use with `PCMG`. 12504b9ad928SBarry Smith 12514b9ad928SBarry Smith Not Collective 12524b9ad928SBarry Smith 12534b9ad928SBarry Smith Input Parameter: 12544b9ad928SBarry Smith . pc - the preconditioner context 12554b9ad928SBarry Smith 1256feefa0e1SJacob Faibussowitsch Output Parameter: 12574b9ad928SBarry Smith . levels - the number of levels 12584b9ad928SBarry Smith 12594b9ad928SBarry Smith Level: advanced 12604b9ad928SBarry Smith 1261562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()` 12624b9ad928SBarry Smith @*/ 1263d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) 1264d71ae5a4SJacob Faibussowitsch { 12654b9ad928SBarry Smith PetscFunctionBegin; 12660700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 12674f572ea9SToby Isaac PetscAssertPointer(levels, 2); 126897d33e41SMatthew G. Knepley *levels = 0; 1269cac4c232SBarry Smith PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels)); 12703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12714b9ad928SBarry Smith } 12724b9ad928SBarry Smith 12734b9ad928SBarry Smith /*@ 1274f1580f4eSBarry Smith PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy 1275e7d4b4cbSMark Adams 1276e7d4b4cbSMark Adams Input Parameter: 1277e7d4b4cbSMark Adams . pc - the preconditioner context 1278e7d4b4cbSMark Adams 127990db8557SMark Adams Output Parameters: 128090db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0 128190db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0 1282e7d4b4cbSMark Adams 1283e7d4b4cbSMark Adams Level: advanced 1284e7d4b4cbSMark Adams 1285f1580f4eSBarry Smith Note: 1286f1580f4eSBarry Smith This is often call the operator complexity in multigrid literature 1287f1580f4eSBarry Smith 1288562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()` 1289e7d4b4cbSMark Adams @*/ 1290d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) 1291d71ae5a4SJacob Faibussowitsch { 1292e7d4b4cbSMark Adams PC_MG *mg = (PC_MG *)pc->data; 1293e7d4b4cbSMark Adams PC_MG_Levels **mglevels = mg->levels; 1294e7d4b4cbSMark Adams PetscInt lev, N; 1295e7d4b4cbSMark Adams PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1296e7d4b4cbSMark Adams MatInfo info; 1297e7d4b4cbSMark Adams 1298e7d4b4cbSMark Adams PetscFunctionBegin; 129990db8557SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 13004f572ea9SToby Isaac if (gc) PetscAssertPointer(gc, 2); 13014f572ea9SToby Isaac if (oc) PetscAssertPointer(oc, 3); 1302e7d4b4cbSMark Adams if (!pc->setupcalled) { 130390db8557SMark Adams if (gc) *gc = 0; 130490db8557SMark Adams if (oc) *oc = 0; 13053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1306e7d4b4cbSMark Adams } 1307e7d4b4cbSMark Adams PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels"); 1308e7d4b4cbSMark Adams for (lev = 0; lev < mg->nlevels; lev++) { 1309e7d4b4cbSMark Adams Mat dB; 13109566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB)); 13119566063dSJacob Faibussowitsch PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */ 13129566063dSJacob Faibussowitsch PetscCall(MatGetSize(dB, &N, NULL)); 1313e7d4b4cbSMark Adams sgc += N; 1314e7d4b4cbSMark Adams soc += info.nz_used; 13159371c9d4SSatish Balay if (lev == mg->nlevels - 1) { 13169371c9d4SSatish Balay nnz0 = info.nz_used; 13179371c9d4SSatish Balay n0 = N; 13189371c9d4SSatish Balay } 1319e7d4b4cbSMark Adams } 13200fdf79fbSJacob Faibussowitsch PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available"); 13210fdf79fbSJacob Faibussowitsch *gc = (PetscReal)(sgc / n0); 132290db8557SMark Adams if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0); 13233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1324e7d4b4cbSMark Adams } 1325e7d4b4cbSMark Adams 1326e7d4b4cbSMark Adams /*@ 132704c3f3b8SBarry Smith PCMGSetType - Determines the form of multigrid to use, either 13284b9ad928SBarry Smith multiplicative, additive, full, or the Kaskade algorithm. 13294b9ad928SBarry Smith 1330c3339decSBarry Smith Logically Collective 13314b9ad928SBarry Smith 13324b9ad928SBarry Smith Input Parameters: 13334b9ad928SBarry Smith + pc - the preconditioner context 1334f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE` 13354b9ad928SBarry Smith 13364b9ad928SBarry Smith Options Database Key: 133720f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade 13384b9ad928SBarry Smith 13394b9ad928SBarry Smith Level: advanced 13404b9ad928SBarry Smith 1341562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType` 13424b9ad928SBarry Smith @*/ 1343d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form) 1344d71ae5a4SJacob Faibussowitsch { 1345f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 13464b9ad928SBarry Smith 13474b9ad928SBarry Smith PetscFunctionBegin; 13480700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1349c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc, form, 2); 135031567311SBarry Smith mg->am = form; 13519dcbbd2bSBarry Smith if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1352c60c7ad4SBarry Smith else pc->ops->applyrichardson = NULL; 13533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1354c60c7ad4SBarry Smith } 1355c60c7ad4SBarry Smith 1356c60c7ad4SBarry Smith /*@ 1357f1580f4eSBarry Smith PCMGGetType - Finds the form of multigrid the `PCMG` is using multiplicative, additive, full, or the Kaskade algorithm. 1358c60c7ad4SBarry Smith 1359c3339decSBarry Smith Logically Collective 1360c60c7ad4SBarry Smith 1361c60c7ad4SBarry Smith Input Parameter: 1362c60c7ad4SBarry Smith . pc - the preconditioner context 1363c60c7ad4SBarry Smith 1364c60c7ad4SBarry Smith Output Parameter: 1365f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType` 1366c60c7ad4SBarry Smith 1367c60c7ad4SBarry Smith Level: advanced 1368c60c7ad4SBarry Smith 1369562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()` 1370c60c7ad4SBarry Smith @*/ 1371d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type) 1372d71ae5a4SJacob Faibussowitsch { 1373c60c7ad4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1374c60c7ad4SBarry Smith 1375c60c7ad4SBarry Smith PetscFunctionBegin; 1376c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1377c60c7ad4SBarry Smith *type = mg->am; 13783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13794b9ad928SBarry Smith } 13804b9ad928SBarry Smith 13814b9ad928SBarry Smith /*@ 1382f1580f4eSBarry Smith PCMGSetCycleType - Sets the type cycles to use. Use `PCMGSetCycleTypeOnLevel()` for more 13834b9ad928SBarry Smith complicated cycling. 13844b9ad928SBarry Smith 1385c3339decSBarry Smith Logically Collective 13864b9ad928SBarry Smith 13874b9ad928SBarry Smith Input Parameters: 1388c2be2410SBarry Smith + pc - the multigrid context 1389f1580f4eSBarry Smith - n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 13904b9ad928SBarry Smith 13914b9ad928SBarry Smith Options Database Key: 1392c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired 13934b9ad928SBarry Smith 13944b9ad928SBarry Smith Level: advanced 13954b9ad928SBarry Smith 1396562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType` 13974b9ad928SBarry Smith @*/ 1398d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) 1399d71ae5a4SJacob Faibussowitsch { 1400f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1401f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 140279416396SBarry Smith PetscInt i, levels; 14034b9ad928SBarry Smith 14044b9ad928SBarry Smith PetscFunctionBegin; 14050700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 140669fbec6eSBarry Smith PetscValidLogicalCollectiveEnum(pc, n, 2); 140728b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1408f3fbd535SBarry Smith levels = mglevels[0]->levels; 14092fa5cd67SKarl Rupp for (i = 0; i < levels; i++) mglevels[i]->cycles = n; 14103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14114b9ad928SBarry Smith } 14124b9ad928SBarry Smith 14138cc2d5dfSBarry Smith /*@ 14148cc2d5dfSBarry Smith PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1415f1580f4eSBarry Smith of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE` 14168cc2d5dfSBarry Smith 1417c3339decSBarry Smith Logically Collective 14188cc2d5dfSBarry Smith 14198cc2d5dfSBarry Smith Input Parameters: 14208cc2d5dfSBarry Smith + pc - the multigrid context 14218cc2d5dfSBarry Smith - n - number of cycles (default is 1) 14228cc2d5dfSBarry Smith 14238cc2d5dfSBarry Smith Options Database Key: 1424147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles 14258cc2d5dfSBarry Smith 14268cc2d5dfSBarry Smith Level: advanced 14278cc2d5dfSBarry Smith 1428f1580f4eSBarry Smith Note: 1429f1580f4eSBarry Smith This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()` 14308cc2d5dfSBarry Smith 1431562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType` 14328cc2d5dfSBarry Smith @*/ 1433d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) 1434d71ae5a4SJacob Faibussowitsch { 1435f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14368cc2d5dfSBarry Smith 14378cc2d5dfSBarry Smith PetscFunctionBegin; 14380700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1439c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 14402a21e185SBarry Smith mg->cyclesperpcapply = n; 14413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14428cc2d5dfSBarry Smith } 14438cc2d5dfSBarry Smith 144466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) 1445d71ae5a4SJacob Faibussowitsch { 1446fb15c04eSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1447fb15c04eSBarry Smith 1448fb15c04eSBarry Smith PetscFunctionBegin; 14492134b1e4SBarry Smith mg->galerkin = use; 14503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1451fb15c04eSBarry Smith } 1452fb15c04eSBarry Smith 1453c2be2410SBarry Smith /*@ 145497177400SBarry Smith PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 145582b87d87SMatthew G. Knepley finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1456c2be2410SBarry Smith 1457c3339decSBarry Smith Logically Collective 1458c2be2410SBarry Smith 1459c2be2410SBarry Smith Input Parameters: 1460c91913d3SJed Brown + pc - the multigrid context 1461f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE` 1462c2be2410SBarry Smith 1463c2be2410SBarry Smith Options Database Key: 1464147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1465c2be2410SBarry Smith 1466c2be2410SBarry Smith Level: intermediate 1467c2be2410SBarry Smith 1468f1580f4eSBarry Smith Note: 1469f1580f4eSBarry Smith Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not 1470f1580f4eSBarry Smith use the `PCMG` construction of the coarser grids. 14711c1aac46SBarry Smith 1472562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType` 1473c2be2410SBarry Smith @*/ 1474d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) 1475d71ae5a4SJacob Faibussowitsch { 1476c2be2410SBarry Smith PetscFunctionBegin; 14770700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1478cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use)); 14793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1480c2be2410SBarry Smith } 1481c2be2410SBarry Smith 14823fc8bf9cSBarry Smith /*@ 1483f1580f4eSBarry Smith PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i 14843fc8bf9cSBarry Smith 14853fc8bf9cSBarry Smith Not Collective 14863fc8bf9cSBarry Smith 14873fc8bf9cSBarry Smith Input Parameter: 14883fc8bf9cSBarry Smith . pc - the multigrid context 14893fc8bf9cSBarry Smith 14903fc8bf9cSBarry Smith Output Parameter: 1491f1580f4eSBarry 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` 14923fc8bf9cSBarry Smith 14933fc8bf9cSBarry Smith Level: intermediate 14943fc8bf9cSBarry Smith 1495562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType` 14963fc8bf9cSBarry Smith @*/ 1497d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) 1498d71ae5a4SJacob Faibussowitsch { 1499f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 15003fc8bf9cSBarry Smith 15013fc8bf9cSBarry Smith PetscFunctionBegin; 15020700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15032134b1e4SBarry Smith *galerkin = mg->galerkin; 15043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15053fc8bf9cSBarry Smith } 15063fc8bf9cSBarry Smith 150766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) 1508d71ae5a4SJacob Faibussowitsch { 1509f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1510f3b08a26SMatthew G. Knepley 1511f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1512f3b08a26SMatthew G. Knepley mg->adaptInterpolation = adapt; 15133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1514f3b08a26SMatthew G. Knepley } 1515f3b08a26SMatthew G. Knepley 151666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) 1517d71ae5a4SJacob Faibussowitsch { 1518f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1519f3b08a26SMatthew G. Knepley 1520f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1521f3b08a26SMatthew G. Knepley *adapt = mg->adaptInterpolation; 15223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1523f3b08a26SMatthew G. Knepley } 1524f3b08a26SMatthew G. Knepley 152566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) 1526d71ae5a4SJacob Faibussowitsch { 15272b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15282b3cbbdaSStefano Zampini 15292b3cbbdaSStefano Zampini PetscFunctionBegin; 15302b3cbbdaSStefano Zampini mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE; 15312b3cbbdaSStefano Zampini mg->coarseSpaceType = ctype; 1532a077d33dSBarry Smith PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH)); 15333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15342b3cbbdaSStefano Zampini } 15352b3cbbdaSStefano Zampini 153666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) 1537d71ae5a4SJacob Faibussowitsch { 15382b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15392b3cbbdaSStefano Zampini 15402b3cbbdaSStefano Zampini PetscFunctionBegin; 15412b3cbbdaSStefano Zampini *ctype = mg->coarseSpaceType; 15423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15432b3cbbdaSStefano Zampini } 15442b3cbbdaSStefano Zampini 154566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) 1546d71ae5a4SJacob Faibussowitsch { 154741b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 154841b6fd38SMatthew G. Knepley 154941b6fd38SMatthew G. Knepley PetscFunctionBegin; 155041b6fd38SMatthew G. Knepley mg->compatibleRelaxation = cr; 15513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 155241b6fd38SMatthew G. Knepley } 155341b6fd38SMatthew G. Knepley 155466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) 1555d71ae5a4SJacob Faibussowitsch { 155641b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 155741b6fd38SMatthew G. Knepley 155841b6fd38SMatthew G. Knepley PetscFunctionBegin; 155941b6fd38SMatthew G. Knepley *cr = mg->compatibleRelaxation; 15603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 156141b6fd38SMatthew G. Knepley } 156241b6fd38SMatthew G. Knepley 1563cc4c1da9SBarry Smith /*@ 15642b3cbbdaSStefano Zampini PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space. 15652b3cbbdaSStefano Zampini 15662b3cbbdaSStefano 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. 15672b3cbbdaSStefano Zampini 1568c3339decSBarry Smith Logically Collective 15692b3cbbdaSStefano Zampini 15702b3cbbdaSStefano Zampini Input Parameters: 15712b3cbbdaSStefano Zampini + pc - the multigrid context 15722b3cbbdaSStefano Zampini - ctype - the type of coarse space 15732b3cbbdaSStefano Zampini 15742b3cbbdaSStefano Zampini Options Database Keys: 15752b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int> - The number of modes to use 1576a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw` 15772b3cbbdaSStefano Zampini 15782b3cbbdaSStefano Zampini Level: intermediate 15792b3cbbdaSStefano Zampini 1580a077d33dSBarry Smith Note: 1581a077d33dSBarry Smith Requires a `DM` with specific functionality be attached to the `PC`. 1582a077d33dSBarry Smith 1583a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM` 15842b3cbbdaSStefano Zampini @*/ 1585d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) 1586d71ae5a4SJacob Faibussowitsch { 15872b3cbbdaSStefano Zampini PetscFunctionBegin; 15882b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15892b3cbbdaSStefano Zampini PetscValidLogicalCollectiveEnum(pc, ctype, 2); 15902b3cbbdaSStefano Zampini PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype)); 15913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15922b3cbbdaSStefano Zampini } 15932b3cbbdaSStefano Zampini 1594cc4c1da9SBarry Smith /*@ 15952b3cbbdaSStefano Zampini PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space. 15962b3cbbdaSStefano Zampini 15972b3cbbdaSStefano Zampini Not Collective 15982b3cbbdaSStefano Zampini 15992b3cbbdaSStefano Zampini Input Parameter: 16002b3cbbdaSStefano Zampini . pc - the multigrid context 16012b3cbbdaSStefano Zampini 16022b3cbbdaSStefano Zampini Output Parameter: 16032b3cbbdaSStefano Zampini . ctype - the type of coarse space 16042b3cbbdaSStefano Zampini 16052b3cbbdaSStefano Zampini Level: intermediate 16062b3cbbdaSStefano Zampini 1607562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()` 16082b3cbbdaSStefano Zampini @*/ 1609d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) 1610d71ae5a4SJacob Faibussowitsch { 16112b3cbbdaSStefano Zampini PetscFunctionBegin; 16122b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16134f572ea9SToby Isaac PetscAssertPointer(ctype, 2); 16142b3cbbdaSStefano Zampini PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype)); 16153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16162b3cbbdaSStefano Zampini } 16172b3cbbdaSStefano Zampini 16182b3cbbdaSStefano Zampini /* MATT: REMOVE? */ 1619f3b08a26SMatthew G. Knepley /*@ 1620f3b08a26SMatthew 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. 1621f3b08a26SMatthew G. Knepley 1622c3339decSBarry Smith Logically Collective 1623f3b08a26SMatthew G. Knepley 1624f3b08a26SMatthew G. Knepley Input Parameters: 1625f3b08a26SMatthew G. Knepley + pc - the multigrid context 1626f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator 1627f3b08a26SMatthew G. Knepley 1628f3b08a26SMatthew G. Knepley Options Database Keys: 1629f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp - Turn on adaptation 1630f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1631f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1632f3b08a26SMatthew G. Knepley 1633f3b08a26SMatthew G. Knepley Level: intermediate 1634f3b08a26SMatthew G. Knepley 1635562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1636f3b08a26SMatthew G. Knepley @*/ 1637d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) 1638d71ae5a4SJacob Faibussowitsch { 1639f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1640f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1641cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt)); 16423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1643f3b08a26SMatthew G. Knepley } 1644f3b08a26SMatthew G. Knepley 1645f3b08a26SMatthew G. Knepley /*@ 1646f1580f4eSBarry Smith PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, 1647f1580f4eSBarry Smith and thus accurately interpolated. 1648f3b08a26SMatthew G. Knepley 164920f4b53cSBarry Smith Not Collective 1650f3b08a26SMatthew G. Knepley 1651f3b08a26SMatthew G. Knepley Input Parameter: 1652f3b08a26SMatthew G. Knepley . pc - the multigrid context 1653f3b08a26SMatthew G. Knepley 1654f3b08a26SMatthew G. Knepley Output Parameter: 1655f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator 1656f3b08a26SMatthew G. Knepley 1657f3b08a26SMatthew G. Knepley Level: intermediate 1658f3b08a26SMatthew G. Knepley 1659562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1660f3b08a26SMatthew G. Knepley @*/ 1661d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) 1662d71ae5a4SJacob Faibussowitsch { 1663f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1664f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16654f572ea9SToby Isaac PetscAssertPointer(adapt, 2); 1666cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt)); 16673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1668f3b08a26SMatthew G. Knepley } 1669f3b08a26SMatthew G. Knepley 16704b9ad928SBarry Smith /*@ 167141b6fd38SMatthew G. Knepley PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 167241b6fd38SMatthew G. Knepley 1673c3339decSBarry Smith Logically Collective 167441b6fd38SMatthew G. Knepley 167541b6fd38SMatthew G. Knepley Input Parameters: 167641b6fd38SMatthew G. Knepley + pc - the multigrid context 167741b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation 167841b6fd38SMatthew G. Knepley 1679f1580f4eSBarry Smith Options Database Key: 168041b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation 168141b6fd38SMatthew G. Knepley 168241b6fd38SMatthew G. Knepley Level: intermediate 168341b6fd38SMatthew G. Knepley 1684562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 168541b6fd38SMatthew G. Knepley @*/ 1686d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) 1687d71ae5a4SJacob Faibussowitsch { 168841b6fd38SMatthew G. Knepley PetscFunctionBegin; 168941b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1690cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr)); 16913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 169241b6fd38SMatthew G. Knepley } 169341b6fd38SMatthew G. Knepley 169441b6fd38SMatthew G. Knepley /*@ 169541b6fd38SMatthew G. Knepley PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 169641b6fd38SMatthew G. Knepley 169720f4b53cSBarry Smith Not Collective 169841b6fd38SMatthew G. Knepley 169941b6fd38SMatthew G. Knepley Input Parameter: 170041b6fd38SMatthew G. Knepley . pc - the multigrid context 170141b6fd38SMatthew G. Knepley 170241b6fd38SMatthew G. Knepley Output Parameter: 170341b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion 170441b6fd38SMatthew G. Knepley 170541b6fd38SMatthew G. Knepley Level: intermediate 170641b6fd38SMatthew G. Knepley 1707562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 170841b6fd38SMatthew G. Knepley @*/ 1709d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) 1710d71ae5a4SJacob Faibussowitsch { 171141b6fd38SMatthew G. Knepley PetscFunctionBegin; 171241b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 17134f572ea9SToby Isaac PetscAssertPointer(cr, 2); 1714cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr)); 17153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 171641b6fd38SMatthew G. Knepley } 171741b6fd38SMatthew G. Knepley 171841b6fd38SMatthew G. Knepley /*@ 171906792cafSBarry Smith PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1720f1580f4eSBarry Smith on all levels. Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of 1721710315b6SLawrence Mitchell pre- and post-smoothing steps. 172206792cafSBarry Smith 1723c3339decSBarry Smith Logically Collective 172406792cafSBarry Smith 172506792cafSBarry Smith Input Parameters: 1726feefa0e1SJacob Faibussowitsch + pc - the multigrid context 172706792cafSBarry Smith - n - the number of smoothing steps 172806792cafSBarry Smith 172906792cafSBarry Smith Options Database Key: 1730a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 173106792cafSBarry Smith 173206792cafSBarry Smith Level: advanced 173306792cafSBarry Smith 1734f1580f4eSBarry Smith Note: 1735f1580f4eSBarry 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. 173606792cafSBarry Smith 1737562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()` 173806792cafSBarry Smith @*/ 1739d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) 1740d71ae5a4SJacob Faibussowitsch { 174106792cafSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 174206792cafSBarry Smith PC_MG_Levels **mglevels = mg->levels; 174306792cafSBarry Smith PetscInt i, levels; 174406792cafSBarry Smith 174506792cafSBarry Smith PetscFunctionBegin; 174606792cafSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 174706792cafSBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 174828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 174906792cafSBarry Smith levels = mglevels[0]->levels; 175006792cafSBarry Smith 175106792cafSBarry Smith for (i = 1; i < levels; i++) { 1752fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 1753fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 175406792cafSBarry Smith mg->default_smoothu = n; 175506792cafSBarry Smith mg->default_smoothd = n; 175606792cafSBarry Smith } 17573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 175806792cafSBarry Smith } 175906792cafSBarry Smith 1760f442ab6aSBarry Smith /*@ 1761f1580f4eSBarry Smith PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels 1762710315b6SLawrence Mitchell and adds the suffix _up to the options name 1763f442ab6aSBarry Smith 1764c3339decSBarry Smith Logically Collective 1765f442ab6aSBarry Smith 1766f1580f4eSBarry Smith Input Parameter: 1767f442ab6aSBarry Smith . pc - the preconditioner context 1768f442ab6aSBarry Smith 1769f442ab6aSBarry Smith Options Database Key: 1770147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1771f442ab6aSBarry Smith 1772f442ab6aSBarry Smith Level: advanced 1773f442ab6aSBarry Smith 1774f1580f4eSBarry Smith Note: 1775f1580f4eSBarry 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. 1776f442ab6aSBarry Smith 1777562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()` 1778f442ab6aSBarry Smith @*/ 1779d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1780d71ae5a4SJacob Faibussowitsch { 1781f442ab6aSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1782f442ab6aSBarry Smith PC_MG_Levels **mglevels = mg->levels; 1783f442ab6aSBarry Smith PetscInt i, levels; 1784f442ab6aSBarry Smith KSP subksp; 1785f442ab6aSBarry Smith 1786f442ab6aSBarry Smith PetscFunctionBegin; 1787f442ab6aSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 178828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1789f442ab6aSBarry Smith levels = mglevels[0]->levels; 1790f442ab6aSBarry Smith 1791f442ab6aSBarry Smith for (i = 1; i < levels; i++) { 1792710315b6SLawrence Mitchell const char *prefix = NULL; 1793f442ab6aSBarry Smith /* make sure smoother up and down are different */ 17949566063dSJacob Faibussowitsch PetscCall(PCMGGetSmootherUp(pc, i, &subksp)); 17959566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix)); 17969566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(subksp, prefix)); 17979566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(subksp, "up_")); 1798f442ab6aSBarry Smith } 17993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1800f442ab6aSBarry Smith } 1801f442ab6aSBarry Smith 180207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 180366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) 1804d71ae5a4SJacob Faibussowitsch { 180507a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 180607a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 180707a4832bSFande Kong Mat *mat; 180807a4832bSFande Kong PetscInt l; 180907a4832bSFande Kong 181007a4832bSFande Kong PetscFunctionBegin; 181128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 18129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 181307a4832bSFande Kong for (l = 1; l < mg->nlevels; l++) { 181407a4832bSFande Kong mat[l - 1] = mglevels[l]->interpolate; 18159566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l - 1])); 181607a4832bSFande Kong } 181707a4832bSFande Kong *num_levels = mg->nlevels; 181807a4832bSFande Kong *interpolations = mat; 18193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 182007a4832bSFande Kong } 182107a4832bSFande Kong 182207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 182366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) 1824d71ae5a4SJacob Faibussowitsch { 182507a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 182607a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 182707a4832bSFande Kong PetscInt l; 182807a4832bSFande Kong Mat *mat; 182907a4832bSFande Kong 183007a4832bSFande Kong PetscFunctionBegin; 183128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 18329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 183307a4832bSFande Kong for (l = 0; l < mg->nlevels - 1; l++) { 1834f4f49eeaSPierre Jolivet PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l])); 18359566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l])); 183607a4832bSFande Kong } 183707a4832bSFande Kong *num_levels = mg->nlevels; 183807a4832bSFande Kong *coarseOperators = mat; 18393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 184007a4832bSFande Kong } 184107a4832bSFande Kong 1842f3b08a26SMatthew G. Knepley /*@C 1843f1580f4eSBarry Smith PCMGRegisterCoarseSpaceConstructor - Adds a method to the `PCMG` package for coarse space construction. 1844f3b08a26SMatthew G. Knepley 1845cc4c1da9SBarry Smith Not Collective, No Fortran Support 1846f3b08a26SMatthew G. Knepley 1847f3b08a26SMatthew G. Knepley Input Parameters: 1848f3b08a26SMatthew G. Knepley + name - name of the constructor 1849*4d4d2bdcSBarry Smith - function - constructor routine, see `PCMGCoarseSpaceConstructorFn` 1850f3b08a26SMatthew G. Knepley 1851f3b08a26SMatthew G. Knepley Level: advanced 1852f3b08a26SMatthew G. Knepley 1853feefa0e1SJacob Faibussowitsch Developer Notes: 1854*4d4d2bdcSBarry Smith This does not appear to be used anywhere 1855f1580f4eSBarry Smith 1856*4d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()` 1857f3b08a26SMatthew G. Knepley @*/ 1858*4d4d2bdcSBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function) 1859d71ae5a4SJacob Faibussowitsch { 1860f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18619566063dSJacob Faibussowitsch PetscCall(PCInitializePackage()); 18629566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function)); 18633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1864f3b08a26SMatthew G. Knepley } 1865f3b08a26SMatthew G. Knepley 1866f3b08a26SMatthew G. Knepley /*@C 1867f3b08a26SMatthew G. Knepley PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1868f3b08a26SMatthew G. Knepley 1869cc4c1da9SBarry Smith Not Collective, No Fortran Support 1870f3b08a26SMatthew G. Knepley 1871f3b08a26SMatthew G. Knepley Input Parameter: 1872f3b08a26SMatthew G. Knepley . name - name of the constructor 1873f3b08a26SMatthew G. Knepley 1874f3b08a26SMatthew G. Knepley Output Parameter: 1875f3b08a26SMatthew G. Knepley . function - constructor routine 1876f3b08a26SMatthew G. Knepley 1877f3b08a26SMatthew G. Knepley Level: advanced 1878f3b08a26SMatthew G. Knepley 1879*4d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()` 1880f3b08a26SMatthew G. Knepley @*/ 1881*4d4d2bdcSBarry Smith PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function) 1882d71ae5a4SJacob Faibussowitsch { 1883f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18849566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function)); 18853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1886f3b08a26SMatthew G. Knepley } 1887f3b08a26SMatthew G. Knepley 18883b09bd56SBarry Smith /*MC 1889ccb205f8SBarry Smith PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 18903b09bd56SBarry Smith information about the coarser grid matrices and restriction/interpolation operators. 18913b09bd56SBarry Smith 18923b09bd56SBarry Smith Options Database Keys: 18933b09bd56SBarry Smith + -pc_mg_levels <nlevels> - number of levels including finest 1894391689abSStefano Zampini . -pc_mg_cycle_type <v,w> - provide the cycle desired 18958c1c2452SJed Brown . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 18963b09bd56SBarry Smith . -pc_mg_log - log information about time spent on each level of the solver 1897710315b6SLawrence Mitchell . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 18982134b1e4SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 18998cf6037eSBarry Smith . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 19008cf6037eSBarry Smith . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1901a3b724e8SBarry Smith to a `PETSCVIEWERSOCKET` for reading from MATLAB. 19028cf6037eSBarry Smith - -pc_mg_dump_binary -dumps the matrices for each level and the restriction/interpolation matrices 19038cf6037eSBarry Smith to the binary output file called binaryoutput 19043b09bd56SBarry Smith 190520f4b53cSBarry Smith Level: intermediate 190620f4b53cSBarry Smith 190795452b02SPatrick Sanan Notes: 190804c3f3b8SBarry Smith The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard 19098f4fb22eSMark Adams options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`, 19108f4fb22eSMark Adams and the finest where `-mg_fine_` can override `-mg_levels_`. One can set different preconditioners etc on specific levels with the prefix 19118f4fb22eSMark Adams `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example 191204c3f3b8SBarry Smith .vb 191304c3f3b8SBarry Smith -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor 191404c3f3b8SBarry Smith .ve 191504c3f3b8SBarry Smith These options also work for controlling the smoothers etc inside `PCGAMG` 191604c3f3b8SBarry Smith 1917f1580f4eSBarry 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 19183b09bd56SBarry Smith 19198cf6037eSBarry Smith When run with a single level the smoother options are used on that level NOT the coarse grid solver options 19208cf6037eSBarry Smith 1921f1580f4eSBarry Smith When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 192223067569SBarry Smith is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 192323067569SBarry Smith (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 192423067569SBarry Smith residual is computed at the end of each cycle. 192523067569SBarry Smith 192604c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE` 1927db781477SPatrick Sanan `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`, 1928db781477SPatrick Sanan `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`, 1929db781477SPatrick Sanan `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, 1930f1580f4eSBarry Smith `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`, 1931f1580f4eSBarry Smith `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 19323b09bd56SBarry Smith M*/ 19333b09bd56SBarry Smith 1934d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1935d71ae5a4SJacob Faibussowitsch { 1936f3fbd535SBarry Smith PC_MG *mg; 1937f3fbd535SBarry Smith 19384b9ad928SBarry Smith PetscFunctionBegin; 19394dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mg)); 19403ec1f749SStefano Zampini pc->data = mg; 1941f3fbd535SBarry Smith mg->nlevels = -1; 194210eca3edSLisandro Dalcin mg->am = PC_MG_MULTIPLICATIVE; 19432134b1e4SBarry Smith mg->galerkin = PC_MG_GALERKIN_NONE; 1944f3b08a26SMatthew G. Knepley mg->adaptInterpolation = PETSC_FALSE; 1945f3b08a26SMatthew G. Knepley mg->Nc = -1; 1946f3b08a26SMatthew G. Knepley mg->eigenvalue = -1; 1947f3fbd535SBarry Smith 194837a44384SMark Adams pc->useAmat = PETSC_TRUE; 194937a44384SMark Adams 19504b9ad928SBarry Smith pc->ops->apply = PCApply_MG; 1951fcb023d4SJed Brown pc->ops->applytranspose = PCApplyTranspose_MG; 195230b0564aSStefano Zampini pc->ops->matapply = PCMatApply_MG; 19534dbf25a8SPierre Jolivet pc->ops->matapplytranspose = PCMatApplyTranspose_MG; 19544b9ad928SBarry Smith pc->ops->setup = PCSetUp_MG; 1955a06653b4SBarry Smith pc->ops->reset = PCReset_MG; 19564b9ad928SBarry Smith pc->ops->destroy = PCDestroy_MG; 19574b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_MG; 19584b9ad928SBarry Smith pc->ops->view = PCView_MG; 1959fb15c04eSBarry Smith 19609566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue)); 19619566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG)); 19629566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG)); 19639566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG)); 19649566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG)); 19659566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG)); 19669566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG)); 19679566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG)); 19689566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG)); 19699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG)); 19702b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG)); 19712b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG)); 19723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19734b9ad928SBarry Smith } 1974