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
PCMGMCycle_Private(PC pc,PC_MG_Levels ** mglevelsin,PetscBool transpose,PetscBool matapp,PCRichardsonConvergedReason * reason)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;
51218e2965SBarry Smith
529566063dSJacob Faibussowitsch PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm));
534b9ad928SBarry Smith if (rnorm <= mg->ttol) {
5470441072SBarry Smith if (rnorm < mg->abstol) {
554d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_ATOL;
569566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol));
574b9ad928SBarry Smith } else {
584d0a8057SBarry Smith *reason = PCRICHARDSON_CONVERGED_RTOL;
599566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n", (double)rnorm, (double)mg->ttol));
604b9ad928SBarry Smith }
613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
624b9ad928SBarry Smith }
634b9ad928SBarry Smith }
644b9ad928SBarry Smith
6531567311SBarry Smith mgc = *(mglevelsin - 1);
669566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
67fcb023d4SJed Brown if (!transpose) {
689566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B));
699566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b));
70fcb023d4SJed Brown } else {
719566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B));
729566063dSJacob Faibussowitsch else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b));
73fcb023d4SJed Brown }
749566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
7530b0564aSStefano Zampini if (matapp) {
7630b0564aSStefano Zampini if (!mgc->X) {
779566063dSJacob Faibussowitsch PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X));
7830b0564aSStefano Zampini } else {
799566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mgc->X));
8030b0564aSStefano Zampini }
8130b0564aSStefano Zampini } else {
829566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mgc->x));
8330b0564aSStefano Zampini }
8448a46eb9SPierre Jolivet while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason));
859566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
86fcb023d4SJed Brown if (!transpose) {
879566063dSJacob Faibussowitsch if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X));
889566063dSJacob Faibussowitsch else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x));
89fcb023d4SJed Brown } else {
909566063dSJacob Faibussowitsch PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x));
91fcb023d4SJed Brown }
929566063dSJacob Faibussowitsch if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
939566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
94fcb023d4SJed Brown if (!transpose) {
9530b0564aSStefano Zampini if (matapp) {
969566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */
979566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL));
9830b0564aSStefano Zampini } else {
999566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */
1009566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
10130b0564aSStefano Zampini }
102fcb023d4SJed Brown } else {
10328b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
1049566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */
1059566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
106fcb023d4SJed Brown }
10741b6fd38SMatthew G. Knepley if (mglevels->cr) {
10820654ebbSStefano Zampini Mat crA;
10920654ebbSStefano Zampini
11028b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
11141b6fd38SMatthew G. Knepley /* TODO Turn on copy and turn off noisy if we have an exact solution
1129566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->x, mglevels->crx));
1139566063dSJacob Faibussowitsch PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
11420654ebbSStefano Zampini PetscCall(KSPGetOperators(mglevels->cr, &crA, NULL));
11520654ebbSStefano Zampini PetscCall(KSPSetNoisy_Private(crA, mglevels->crx));
1169566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1179566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11841b6fd38SMatthew G. Knepley }
1199566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1204b9ad928SBarry Smith }
1213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1224b9ad928SBarry Smith }
1234b9ad928SBarry Smith
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 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)
125d71ae5a4SJacob Faibussowitsch {
126f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
127f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels;
128391689abSStefano Zampini PC tpc;
129391689abSStefano Zampini PetscBool changeu, changed;
130f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i;
1314b9ad928SBarry Smith
1324b9ad928SBarry Smith PetscFunctionBegin;
133a762d673SBarry Smith /* When the DM is supplying the matrix then it will not exist until here */
134a762d673SBarry Smith for (i = 0; i < levels; i++) {
135a762d673SBarry Smith if (!mglevels[i]->A) {
1369566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1379566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
138a762d673SBarry Smith }
139a762d673SBarry Smith }
140391689abSStefano Zampini
1419566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1429566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1439566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1449566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
145391689abSStefano Zampini if (!changed && !changeu) {
1469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b));
147f3fbd535SBarry Smith mglevels[levels - 1]->b = b;
148391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
149391689abSStefano Zampini if (!mglevels[levels - 1]->b) {
150391689abSStefano Zampini Vec *vec;
151391689abSStefano Zampini
1529566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
153391689abSStefano Zampini mglevels[levels - 1]->b = *vec;
1549566063dSJacob Faibussowitsch PetscCall(PetscFree(vec));
155391689abSStefano Zampini }
1569566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b));
157391689abSStefano Zampini }
158f3fbd535SBarry Smith mglevels[levels - 1]->x = x;
1594b9ad928SBarry Smith
16031567311SBarry Smith mg->rtol = rtol;
16131567311SBarry Smith mg->abstol = abstol;
16231567311SBarry Smith mg->dtol = dtol;
1634b9ad928SBarry Smith if (rtol) {
1644b9ad928SBarry Smith /* compute initial residual norm for relative convergence test */
1654b9ad928SBarry Smith PetscReal rnorm;
166218e2965SBarry Smith
1677319c654SBarry Smith if (zeroguess) {
1689566063dSJacob Faibussowitsch PetscCall(VecNorm(b, NORM_2, &rnorm));
1697319c654SBarry Smith } else {
1709566063dSJacob Faibussowitsch PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1719566063dSJacob Faibussowitsch PetscCall(VecNorm(w, NORM_2, &rnorm));
1727319c654SBarry Smith }
17331567311SBarry Smith mg->ttol = PetscMax(rtol * rnorm, abstol);
1742fa5cd67SKarl Rupp } else if (abstol) mg->ttol = abstol;
1752fa5cd67SKarl Rupp else mg->ttol = 0.0;
1764b9ad928SBarry Smith
1774d0a8057SBarry Smith /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
178336babb1SJed Brown stop prematurely due to small residual */
1794d0a8057SBarry Smith for (i = 1; i < levels; i++) {
180fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
181f3fbd535SBarry Smith if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
18223067569SBarry Smith /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1839566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
184fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
1854b9ad928SBarry Smith }
1864d0a8057SBarry Smith }
1874d0a8057SBarry Smith
188dd460d27SBarry Smith *reason = PCRICHARDSON_NOT_SET;
1894d0a8057SBarry Smith for (i = 0; i < its; i++) {
1909566063dSJacob Faibussowitsch PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1914d0a8057SBarry Smith if (*reason) break;
1924d0a8057SBarry Smith }
193dd460d27SBarry Smith if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS;
1944d0a8057SBarry Smith *outits = i;
195391689abSStefano Zampini if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1974b9ad928SBarry Smith }
1984b9ad928SBarry Smith
PCReset_MG(PC pc)199d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc)
200d71ae5a4SJacob Faibussowitsch {
2013aeaf226SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
2023aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels;
2032b3cbbdaSStefano Zampini PetscInt i, n;
2043aeaf226SBarry Smith
2053aeaf226SBarry Smith PetscFunctionBegin;
2063aeaf226SBarry Smith if (mglevels) {
2073aeaf226SBarry Smith n = mglevels[0]->levels;
2083aeaf226SBarry Smith for (i = 0; i < n - 1; i++) {
2099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->r));
2109566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->b));
2119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->x));
2129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->R));
2139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B));
2149566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X));
2159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crx));
2169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i]->crb));
2179566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2189566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2199566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2213aeaf226SBarry Smith }
2229566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2239566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->crb));
224391689abSStefano Zampini /* this is not null only if the smoother on the finest level
225391689abSStefano Zampini changes the rhs during PreSolve */
2269566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[n - 1]->b));
2279566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[n - 1]->B));
2283aeaf226SBarry Smith
2293aeaf226SBarry Smith for (i = 0; i < n; i++) {
2302b3cbbdaSStefano Zampini PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2319566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->A));
23248a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2339566063dSJacob Faibussowitsch PetscCall(KSPReset(mglevels[i]->smoothu));
2349566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2353aeaf226SBarry Smith }
236f3b08a26SMatthew G. Knepley mg->Nc = 0;
2373aeaf226SBarry Smith }
2383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2393aeaf226SBarry Smith }
2403aeaf226SBarry Smith
24141b6fd38SMatthew G. Knepley /* Implementing CR
24241b6fd38SMatthew G. Knepley
24341b6fd38SMatthew 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
24441b6fd38SMatthew G. Knepley
24541b6fd38SMatthew G. Knepley Inj^T (Inj Inj^T)^{-1} Inj
24641b6fd38SMatthew G. Knepley
24741b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24841b6fd38SMatthew G. Knepley
24941b6fd38SMatthew G. Knepley Inj^T Inj
25041b6fd38SMatthew G. Knepley
25141b6fd38SMatthew G. Knepley and
25241b6fd38SMatthew G. Knepley
25341b6fd38SMatthew G. Knepley S = I - Inj^T Inj
25441b6fd38SMatthew G. Knepley
25541b6fd38SMatthew G. Knepley since
25641b6fd38SMatthew G. Knepley
25741b6fd38SMatthew G. Knepley Inj S = Inj - (Inj Inj^T) Inj = 0.
25841b6fd38SMatthew G. Knepley
25941b6fd38SMatthew G. Knepley Brannick suggests
26041b6fd38SMatthew G. Knepley
26141b6fd38SMatthew G. Knepley A \to S^T A S \qquad\mathrm{and}\qquad M \to S^T M S
26241b6fd38SMatthew G. Knepley
26341b6fd38SMatthew 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
26441b6fd38SMatthew G. Knepley
26541b6fd38SMatthew G. Knepley M^{-1} A \to S M^{-1} A S
26641b6fd38SMatthew G. Knepley
26741b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26841b6fd38SMatthew G. Knepley
26941b6fd38SMatthew G. Knepley Check: || Inj P - I ||_F < tol
27041b6fd38SMatthew G. Knepley Check: In general, Inj Inj^T = I
27141b6fd38SMatthew G. Knepley */
27241b6fd38SMatthew G. Knepley
27341b6fd38SMatthew G. Knepley typedef struct {
27441b6fd38SMatthew G. Knepley PC mg; /* The PCMG object */
27541b6fd38SMatthew G. Knepley PetscInt l; /* The multigrid level for this solver */
27641b6fd38SMatthew G. Knepley Mat Inj; /* The injection matrix */
27741b6fd38SMatthew G. Knepley Mat S; /* I - Inj^T Inj */
27841b6fd38SMatthew G. Knepley } CRContext;
27941b6fd38SMatthew G. Knepley
CRSetup_Private(PC pc)280d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc)
281d71ae5a4SJacob Faibussowitsch {
28241b6fd38SMatthew G. Knepley CRContext *ctx;
28341b6fd38SMatthew G. Knepley Mat It;
28441b6fd38SMatthew G. Knepley
28541b6fd38SMatthew G. Knepley PetscFunctionBeginUser;
2869566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx));
2879566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28828b400f6SJacob Faibussowitsch PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2899566063dSJacob Faibussowitsch PetscCall(MatCreateTranspose(It, &ctx->Inj));
2909566063dSJacob Faibussowitsch PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2919566063dSJacob Faibussowitsch PetscCall(MatScale(ctx->S, -1.0));
2929566063dSJacob Faibussowitsch PetscCall(MatShift(ctx->S, 1.0));
2933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
29441b6fd38SMatthew G. Knepley }
29541b6fd38SMatthew G. Knepley
CRApply_Private(PC pc,Vec x,Vec y)296d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
297d71ae5a4SJacob Faibussowitsch {
29841b6fd38SMatthew G. Knepley CRContext *ctx;
29941b6fd38SMatthew G. Knepley
30041b6fd38SMatthew G. Knepley PetscFunctionBeginUser;
3019566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx));
3029566063dSJacob Faibussowitsch PetscCall(MatMult(ctx->S, x, y));
3033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
30441b6fd38SMatthew G. Knepley }
30541b6fd38SMatthew G. Knepley
CRDestroy_Private(PC pc)306d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc)
307d71ae5a4SJacob Faibussowitsch {
30841b6fd38SMatthew G. Knepley CRContext *ctx;
30941b6fd38SMatthew G. Knepley
31041b6fd38SMatthew G. Knepley PetscFunctionBeginUser;
3119566063dSJacob Faibussowitsch PetscCall(PCShellGetContext(pc, &ctx));
3129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->Inj));
3139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->S));
3149566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx));
3159566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(pc, NULL));
3163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
31741b6fd38SMatthew G. Knepley }
31841b6fd38SMatthew G. Knepley
CreateCR_Private(PC pc,PetscInt l,PC * cr)319d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
320d71ae5a4SJacob Faibussowitsch {
32141b6fd38SMatthew G. Knepley CRContext *ctx;
32241b6fd38SMatthew G. Knepley
32341b6fd38SMatthew G. Knepley PetscFunctionBeginUser;
3249566063dSJacob Faibussowitsch PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3259566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3269566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(1, &ctx));
32741b6fd38SMatthew G. Knepley ctx->mg = pc;
32841b6fd38SMatthew G. Knepley ctx->l = l;
3299566063dSJacob Faibussowitsch PetscCall(PCSetType(*cr, PCSHELL));
3309566063dSJacob Faibussowitsch PetscCall(PCShellSetContext(*cr, ctx));
3319566063dSJacob Faibussowitsch PetscCall(PCShellSetApply(*cr, CRApply_Private));
3329566063dSJacob Faibussowitsch PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3339566063dSJacob Faibussowitsch PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
3343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
33541b6fd38SMatthew G. Knepley }
33641b6fd38SMatthew G. Knepley
3378f4fb22eSMark Adams PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *);
3388f4fb22eSMark Adams
PCMGSetLevels_MG(PC pc,PetscInt levels,MPI_Comm * comms)339d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms)
340d71ae5a4SJacob Faibussowitsch {
341f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
342ce94432eSBarry Smith MPI_Comm comm;
3433aeaf226SBarry Smith PC_MG_Levels **mglevels = mg->levels;
34410eca3edSLisandro Dalcin PCMGType mgtype = mg->am;
34510167fecSBarry Smith PetscInt mgctype = (PetscInt)PC_MG_CYCLE_V;
346f3fbd535SBarry Smith PetscInt i;
347f3fbd535SBarry Smith PetscMPIInt size;
348f3fbd535SBarry Smith const char *prefix;
349f3fbd535SBarry Smith PC ipc;
3503aeaf226SBarry Smith PetscInt n;
3514b9ad928SBarry Smith
3524b9ad928SBarry Smith PetscFunctionBegin;
3530700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
354548767e0SJed Brown PetscValidLogicalCollectiveInt(pc, levels, 2);
3553ba16761SJacob Faibussowitsch if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS);
3569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3573aeaf226SBarry Smith if (mglevels) {
35810eca3edSLisandro Dalcin mgctype = mglevels[0]->cycles;
3593aeaf226SBarry Smith /* changing the number of levels so free up the previous stuff */
3609566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc));
3613aeaf226SBarry Smith n = mglevels[0]->levels;
3623aeaf226SBarry Smith for (i = 0; i < n; i++) {
36348a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3649566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3659566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr));
3669566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i]));
3673aeaf226SBarry Smith }
3689566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels));
3693aeaf226SBarry Smith }
370f3fbd535SBarry Smith
371f3fbd535SBarry Smith mg->nlevels = levels;
372f3fbd535SBarry Smith
3739566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(levels, &mglevels));
374f3fbd535SBarry Smith
3759566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix));
376f3fbd535SBarry Smith
377a9db87a2SMatthew G Knepley mg->stageApply = 0;
378f3fbd535SBarry Smith for (i = 0; i < levels; i++) {
3794dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mglevels[i]));
3802fa5cd67SKarl Rupp
381f3fbd535SBarry Smith mglevels[i]->level = i;
382f3fbd535SBarry Smith mglevels[i]->levels = levels;
38310eca3edSLisandro Dalcin mglevels[i]->cycles = mgctype;
384336babb1SJed Brown mg->default_smoothu = 2;
385336babb1SJed Brown mg->default_smoothd = 2;
38663e6d426SJed Brown mglevels[i]->eventsmoothsetup = 0;
38763e6d426SJed Brown mglevels[i]->eventsmoothsolve = 0;
38863e6d426SJed Brown mglevels[i]->eventresidual = 0;
38963e6d426SJed Brown mglevels[i]->eventinterprestrict = 0;
390f3fbd535SBarry Smith
391f3fbd535SBarry Smith if (comms) comm = comms[i];
392d5a8f7e6SBarry Smith if (comm != MPI_COMM_NULL) {
3939566063dSJacob Faibussowitsch PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3943821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel));
3959566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3969566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3979566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3998f4fb22eSMark Adams if (i == 0 && levels > 1) { // coarse grid
4009566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
401f3fbd535SBarry Smith
4029dbfc187SHong Zhang /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4039566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4049566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4059566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size));
406f3fbd535SBarry Smith if (size > 1) {
4079566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCREDUNDANT));
408f3fbd535SBarry Smith } else {
4099566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCLU));
410f3fbd535SBarry Smith }
4119566063dSJacob Faibussowitsch PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
4128f4fb22eSMark Adams } else {
4138f4fb22eSMark Adams char tprefix[128];
4148f4fb22eSMark Adams
4158f4fb22eSMark Adams PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
4168f4fb22eSMark Adams PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
4178f4fb22eSMark Adams PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
4188f4fb22eSMark Adams PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
4198f4fb22eSMark Adams PetscCall(PCSetType(ipc, PCSOR));
420fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
4218f4fb22eSMark Adams
4228f4fb22eSMark Adams if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_'
4238f4fb22eSMark Adams PetscBool set;
424218e2965SBarry Smith
4258f4fb22eSMark Adams PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set));
4268f4fb22eSMark Adams if (set) {
4278f4fb22eSMark Adams if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix));
4288f4fb22eSMark Adams else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_"));
4298f4fb22eSMark Adams PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix));
4308f4fb22eSMark Adams } else {
431835f2295SStefano Zampini PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4328f4fb22eSMark Adams PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4338f4fb22eSMark Adams }
4348f4fb22eSMark Adams } else {
435835f2295SStefano Zampini PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4368f4fb22eSMark Adams PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4378f4fb22eSMark Adams }
438f3fbd535SBarry Smith }
439d5a8f7e6SBarry Smith }
440f3fbd535SBarry Smith mglevels[i]->smoothu = mglevels[i]->smoothd;
44131567311SBarry Smith mg->rtol = 0.0;
44231567311SBarry Smith mg->abstol = 0.0;
44331567311SBarry Smith mg->dtol = 0.0;
44431567311SBarry Smith mg->ttol = 0.0;
44531567311SBarry Smith mg->cyclesperpcapply = 1;
446f3fbd535SBarry Smith }
447f3fbd535SBarry Smith mg->levels = mglevels;
4489566063dSJacob Faibussowitsch PetscCall(PCMGSetType(pc, mgtype));
4493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4504b9ad928SBarry Smith }
4514b9ad928SBarry Smith
45297d33e41SMatthew G. Knepley /*@C
453f1580f4eSBarry Smith PCMGSetLevels - Sets the number of levels to use with `PCMG`.
454f1580f4eSBarry Smith Must be called before any other `PCMG` routine.
45597d33e41SMatthew G. Knepley
456c3339decSBarry Smith Logically Collective
45797d33e41SMatthew G. Knepley
45897d33e41SMatthew G. Knepley Input Parameters:
45997d33e41SMatthew G. Knepley + pc - the preconditioner context
46097d33e41SMatthew G. Knepley . levels - the number of levels
46197d33e41SMatthew G. Knepley - comms - optional communicators for each level; this is to allow solving the coarser problems
462d5a8f7e6SBarry Smith on smaller sets of processes. For processes that are not included in the computation
46320f4b53cSBarry Smith you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes
46405552d4bSJunchao Zhang should participate in each level of problem.
46597d33e41SMatthew G. Knepley
466efba3485SBarry Smith Options Database Key:
467efba3485SBarry Smith . -pc_mg_levels <levels> - set the number of levels to use
468efba3485SBarry Smith
46997d33e41SMatthew G. Knepley Level: intermediate
47097d33e41SMatthew G. Knepley
47197d33e41SMatthew G. Knepley Notes:
47220f4b53cSBarry Smith If the number of levels is one then the multigrid uses the `-mg_levels` prefix
4738f4fb22eSMark Adams for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix.
47497d33e41SMatthew G. Knepley
475d5a8f7e6SBarry Smith You can free the information in comms after this routine is called.
476d5a8f7e6SBarry Smith
477f1580f4eSBarry Smith The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
478d5a8f7e6SBarry Smith are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
479d5a8f7e6SBarry Smith the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
480d5a8f7e6SBarry Smith of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
481f1580f4eSBarry Smith the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
482d5a8f7e6SBarry Smith in the coarse grid solve.
483d5a8f7e6SBarry Smith
484f1580f4eSBarry Smith Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
485d5a8f7e6SBarry Smith must take special care in providing the restriction and interpolation operation. We recommend
486d5a8f7e6SBarry Smith providing these as two step operations; first perform a standard restriction or interpolation on
487d5a8f7e6SBarry Smith the full number of ranks for that level and then use an MPI call to copy the resulting vector
48805552d4bSJunchao Zhang array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
489d5a8f7e6SBarry Smith cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
49020f4b53cSBarry Smith receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries.
491d5a8f7e6SBarry Smith
492feefa0e1SJacob Faibussowitsch Fortran Notes:
49320f4b53cSBarry Smith Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM`
494f1580f4eSBarry Smith is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
495d5a8f7e6SBarry Smith
496562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()`
49797d33e41SMatthew G. Knepley @*/
PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm * comms)498d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms)
499d71ae5a4SJacob Faibussowitsch {
50097d33e41SMatthew G. Knepley PetscFunctionBegin;
50197d33e41SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5024f572ea9SToby Isaac if (comms) PetscAssertPointer(comms, 3);
503cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
5043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
50597d33e41SMatthew G. Knepley }
50697d33e41SMatthew G. Knepley
PCDestroy_MG(PC pc)507d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc)
508d71ae5a4SJacob Faibussowitsch {
509a06653b4SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
510a06653b4SBarry Smith PC_MG_Levels **mglevels = mg->levels;
511a06653b4SBarry Smith PetscInt i, n;
512c07bf074SBarry Smith
513c07bf074SBarry Smith PetscFunctionBegin;
5149566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc));
515a06653b4SBarry Smith if (mglevels) {
516a06653b4SBarry Smith n = mglevels[0]->levels;
517a06653b4SBarry Smith for (i = 0; i < n; i++) {
51848a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
5199566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu));
5209566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr));
5219566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i]));
522a06653b4SBarry Smith }
5239566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels));
524a06653b4SBarry Smith }
5259566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data));
5269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5282b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
529bbbcb081SMark Adams PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", NULL));
5302b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5312b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5322b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5332b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5342b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5352b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5362b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5372b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5382b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5392b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
541f3fbd535SBarry Smith }
542f3fbd535SBarry Smith
543f3fbd535SBarry Smith /*
544f3fbd535SBarry Smith PCApply_MG - Runs either an additive, multiplicative, Kaskadic
545f3fbd535SBarry Smith or full cycle of multigrid.
546f3fbd535SBarry Smith
547f3fbd535SBarry Smith Note:
548f3fbd535SBarry Smith A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
549f3fbd535SBarry Smith */
PCApply_MG_Internal(PC pc,Vec b,Vec x,Mat B,Mat X,PetscBool transpose)550d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
551d71ae5a4SJacob Faibussowitsch {
552f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
553f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels;
554391689abSStefano Zampini PC tpc;
555f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i;
55630b0564aSStefano Zampini PetscBool changeu, changed, matapp;
557f3fbd535SBarry Smith
558f3fbd535SBarry Smith PetscFunctionBegin;
55930b0564aSStefano Zampini matapp = (PetscBool)(B && X);
5609566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
561e1d8e5deSBarry Smith /* When the DM is supplying the matrix then it will not exist until here */
562298cc208SBarry Smith for (i = 0; i < levels; i++) {
563e1d8e5deSBarry Smith if (!mglevels[i]->A) {
5649566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5659566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
566e1d8e5deSBarry Smith }
567e1d8e5deSBarry Smith }
568e1d8e5deSBarry Smith
5699566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5709566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5719566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5729566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
573391689abSStefano Zampini if (!changeu && !changed) {
57430b0564aSStefano Zampini if (matapp) {
5759566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->B));
57630b0564aSStefano Zampini mglevels[levels - 1]->B = B;
57730b0564aSStefano Zampini } else {
5789566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b));
579f3fbd535SBarry Smith mglevels[levels - 1]->b = b;
58030b0564aSStefano Zampini }
581391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
58230b0564aSStefano Zampini if (matapp) {
58330b0564aSStefano Zampini if (mglevels[levels - 1]->B) {
58430b0564aSStefano Zampini PetscInt N1, N2;
58530b0564aSStefano Zampini PetscBool flg;
58630b0564aSStefano Zampini
5879566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5889566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N2));
5899566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
59048a46eb9SPierre Jolivet if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
59130b0564aSStefano Zampini }
59230b0564aSStefano Zampini if (!mglevels[levels - 1]->B) {
5939566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
59430b0564aSStefano Zampini } else {
5959566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
59630b0564aSStefano Zampini }
59730b0564aSStefano Zampini } else {
598391689abSStefano Zampini if (!mglevels[levels - 1]->b) {
599391689abSStefano Zampini Vec *vec;
600391689abSStefano Zampini
6019566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
602391689abSStefano Zampini mglevels[levels - 1]->b = *vec;
6039566063dSJacob Faibussowitsch PetscCall(PetscFree(vec));
604391689abSStefano Zampini }
6059566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b));
606391689abSStefano Zampini }
60730b0564aSStefano Zampini }
6089371c9d4SSatish Balay if (matapp) {
6099371c9d4SSatish Balay mglevels[levels - 1]->X = X;
6109371c9d4SSatish Balay } else {
6119371c9d4SSatish Balay mglevels[levels - 1]->x = x;
6129371c9d4SSatish Balay }
61330b0564aSStefano Zampini
61430b0564aSStefano Zampini /* If coarser Xs are present, it means we have already block applied the PC at least once
61530b0564aSStefano Zampini Reset operators if sizes/type do no match */
61630b0564aSStefano Zampini if (matapp && levels > 1 && mglevels[levels - 2]->X) {
61730b0564aSStefano Zampini PetscInt Xc, Bc;
61830b0564aSStefano Zampini PetscBool flg;
61930b0564aSStefano Zampini
6209566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
6219566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
6229566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
62330b0564aSStefano Zampini if (Xc != Bc || !flg) {
6249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->R));
62530b0564aSStefano Zampini for (i = 0; i < levels - 1; i++) {
6269566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->R));
6279566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B));
6289566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X));
62930b0564aSStefano Zampini }
63030b0564aSStefano Zampini }
63130b0564aSStefano Zampini }
632391689abSStefano Zampini
63331567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) {
6349566063dSJacob Faibussowitsch if (matapp) PetscCall(MatZeroEntries(X));
6359566063dSJacob Faibussowitsch else PetscCall(VecZeroEntries(x));
63648a46eb9SPierre Jolivet for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6372fa5cd67SKarl Rupp } else if (mg->am == PC_MG_ADDITIVE) {
6389566063dSJacob Faibussowitsch PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6392fa5cd67SKarl Rupp } else if (mg->am == PC_MG_KASKADE) {
6409566063dSJacob Faibussowitsch PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6412fa5cd67SKarl Rupp } else {
6429566063dSJacob Faibussowitsch PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
643f3fbd535SBarry Smith }
6449566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePop());
64530b0564aSStefano Zampini if (!changeu && !changed) {
6469371c9d4SSatish Balay if (matapp) {
6479371c9d4SSatish Balay mglevels[levels - 1]->B = NULL;
6489371c9d4SSatish Balay } else {
6499371c9d4SSatish Balay mglevels[levels - 1]->b = NULL;
6509371c9d4SSatish Balay }
65130b0564aSStefano Zampini }
6523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
653f3fbd535SBarry Smith }
654f3fbd535SBarry Smith
PCApply_MG(PC pc,Vec b,Vec x)655d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
656d71ae5a4SJacob Faibussowitsch {
657fcb023d4SJed Brown PetscFunctionBegin;
6589566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
660fcb023d4SJed Brown }
661fcb023d4SJed Brown
PCApplyTranspose_MG(PC pc,Vec b,Vec x)662d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
663d71ae5a4SJacob Faibussowitsch {
664fcb023d4SJed Brown PetscFunctionBegin;
6659566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
66730b0564aSStefano Zampini }
66830b0564aSStefano Zampini
PCMatApply_MG(PC pc,Mat b,Mat x)669d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
670d71ae5a4SJacob Faibussowitsch {
67130b0564aSStefano Zampini PetscFunctionBegin;
6729566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
674fcb023d4SJed Brown }
675f3fbd535SBarry Smith
PCMatApplyTranspose_MG(PC pc,Mat b,Mat x)6764dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x)
6774dbf25a8SPierre Jolivet {
6784dbf25a8SPierre Jolivet PetscFunctionBegin;
6794dbf25a8SPierre Jolivet PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE));
6804dbf25a8SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS);
6814dbf25a8SPierre Jolivet }
6824dbf25a8SPierre Jolivet
PCSetFromOptions_MG(PC pc,PetscOptionItems PetscOptionsObject)683ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject)
684d71ae5a4SJacob Faibussowitsch {
685710315b6SLawrence Mitchell PetscInt levels, cycles;
686f3b08a26SMatthew G. Knepley PetscBool flg, flg2;
687f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
6883d3eaba7SBarry Smith PC_MG_Levels **mglevels;
689f3fbd535SBarry Smith PCMGType mgtype;
690f3fbd535SBarry Smith PCMGCycleType mgctype;
6912134b1e4SBarry Smith PCMGGalerkinType gtype;
6922b3cbbdaSStefano Zampini PCMGCoarseSpaceType coarseSpaceType;
693f3fbd535SBarry Smith
694f3fbd535SBarry Smith PetscFunctionBegin;
6951d743356SStefano Zampini levels = PetscMax(mg->nlevels, 1);
696d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6979566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6981a97d7b6SStefano Zampini if (!flg && !mg->levels && pc->dm) {
6999566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels));
700eb3f98d2SBarry Smith levels++;
7013aeaf226SBarry Smith mg->usedmfornumberoflevels = PETSC_TRUE;
702eb3f98d2SBarry Smith }
7039566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL));
7043aeaf226SBarry Smith mglevels = mg->levels;
7053aeaf226SBarry Smith
706f3fbd535SBarry Smith mgctype = (PCMGCycleType)mglevels[0]->cycles;
7079566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
7081baa6e33SBarry Smith if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
7092b3cbbdaSStefano Zampini coarseSpaceType = mg->coarseSpaceType;
7102b3cbbdaSStefano 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));
7112b3cbbdaSStefano Zampini if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
7129566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
7139566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
71441b6fd38SMatthew G. Knepley flg2 = PETSC_FALSE;
7159566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
7169566063dSJacob Faibussowitsch if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
717f56b1265SBarry Smith flg = PETSC_FALSE;
7189566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
7191baa6e33SBarry Smith if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
7205544a5bcSStefano Zampini PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)>ype, &flg));
7215544a5bcSStefano Zampini if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
72231567311SBarry Smith mgtype = mg->am;
7239566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
7241baa6e33SBarry Smith if (flg) PetscCall(PCMGSetType(pc, mgtype));
72531567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) {
7269566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
7271baa6e33SBarry Smith if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
728f3fbd535SBarry Smith }
729f3fbd535SBarry Smith flg = PETSC_FALSE;
7309566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
731f3fbd535SBarry Smith if (flg) {
732f3fbd535SBarry Smith PetscInt i;
733f3fbd535SBarry Smith char eventname[128];
7341a97d7b6SStefano Zampini
735f3fbd535SBarry Smith levels = mglevels[0]->levels;
736f3fbd535SBarry Smith for (i = 0; i < levels; i++) {
737835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i));
7389566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
739835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i));
7409566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
741f3fbd535SBarry Smith if (i) {
742835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i));
7439566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
744835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i));
7459566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
746f3fbd535SBarry Smith }
747f3fbd535SBarry Smith }
748eec35531SMatthew G Knepley
7492611ad71SToby Isaac if (PetscDefined(USE_LOG)) {
7502611ad71SToby Isaac const char sname[] = "MG Apply";
751eec35531SMatthew G Knepley
7522611ad71SToby Isaac PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
7532611ad71SToby Isaac if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
754eec35531SMatthew G Knepley }
755f3fbd535SBarry Smith }
756d0609cedSBarry Smith PetscOptionsHeadEnd();
757f3b08a26SMatthew G. Knepley /* Check option consistency */
7589566063dSJacob Faibussowitsch PetscCall(PCMGGetGalerkin(pc, >ype));
7599566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
76008401ef6SPierre Jolivet PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
762f3fbd535SBarry Smith }
763f3fbd535SBarry Smith
7640a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7650a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7660a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7672b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
768f3fbd535SBarry Smith
7699804daf3SBarry Smith #include <petscdraw.h>
PCView_MG(PC pc,PetscViewer viewer)770d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
771d71ae5a4SJacob Faibussowitsch {
772f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
773f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels;
774e3deeeafSJed Brown PetscInt levels = mglevels ? mglevels[0]->levels : 0, i;
7759f196a02SMartin Diehl PetscBool isascii, isbinary, isdraw;
776f3fbd535SBarry Smith
777f3fbd535SBarry Smith PetscFunctionBegin;
7789f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
7799566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7809566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
7819f196a02SMartin Diehl if (isascii) {
782e3deeeafSJed Brown const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
783bcefaa27SBarry Smith
784bcefaa27SBarry Smith if (levels == 1) PetscCall(PetscViewerASCIIPrintf(viewer, " WARNING: Multigrid is being run with only a single level!\n"));
78563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
78648a46eb9SPierre Jolivet if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7872134b1e4SBarry Smith if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7889566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n"));
7892134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7909566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n"));
7912134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7929566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n"));
7932134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7949566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n"));
7954f66f45eSBarry Smith } else {
7969566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n"));
797f3fbd535SBarry Smith }
7981baa6e33SBarry Smith if (mg->view) PetscCall((*mg->view)(pc, viewer));
799f3fbd535SBarry Smith for (i = 0; i < levels; i++) {
80063a3b9bcSJacob Faibussowitsch if (i) {
80163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
802f3fbd535SBarry Smith } else {
80363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
804f3fbd535SBarry Smith }
8059566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
8069566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8079566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
808f3fbd535SBarry Smith if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
8099566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
810f3fbd535SBarry Smith } else if (i) {
81163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
8129566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
8139566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8149566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
815f3fbd535SBarry Smith }
81641b6fd38SMatthew G. Knepley if (i && mglevels[i]->cr) {
81763a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
8189566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
8199566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->cr, viewer));
8209566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
82141b6fd38SMatthew G. Knepley }
822f3fbd535SBarry Smith }
8235b0b0462SBarry Smith } else if (isbinary) {
8245b0b0462SBarry Smith for (i = levels - 1; i >= 0; i--) {
8259566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer));
82648a46eb9SPierre Jolivet if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8275b0b0462SBarry Smith }
828219b1045SBarry Smith } else if (isdraw) {
829219b1045SBarry Smith PetscDraw draw;
830b4375e8dSPeter Brune PetscReal x, w, y, bottom, th;
8319566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8329566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8339566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
834219b1045SBarry Smith bottom = y - th;
835219b1045SBarry Smith for (i = levels - 1; i >= 0; i--) {
836b4375e8dSPeter Brune if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8379566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8389566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8399566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
840b4375e8dSPeter Brune } else {
841b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x);
8429566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8439566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8449566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
8459566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8469566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8479566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
848b4375e8dSPeter Brune }
8499566063dSJacob Faibussowitsch PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8501cd381d6SBarry Smith bottom -= th;
851219b1045SBarry Smith }
8525b0b0462SBarry Smith }
8533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
854f3fbd535SBarry Smith }
855f3fbd535SBarry Smith
856af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
857cab2e9ccSBarry Smith
858f3fbd535SBarry Smith /*
859f3fbd535SBarry Smith Calls setup for the KSP on each level
860f3fbd535SBarry Smith */
PCSetUp_MG(PC pc)861d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
862d71ae5a4SJacob Faibussowitsch {
863f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
864f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels;
8651a97d7b6SStefano Zampini PetscInt i, n;
86698e04984SBarry Smith PC cpc;
8673db492dfSBarry Smith PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
868f3fbd535SBarry Smith Mat dA, dB;
869f3fbd535SBarry Smith Vec tvec;
870218a07d4SBarry Smith DM *dms;
8710a545947SLisandro Dalcin PetscViewer viewer = NULL;
87241b6fd38SMatthew G. Knepley PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8732b3cbbdaSStefano Zampini PetscBool adaptInterpolation = mg->adaptInterpolation;
874f3fbd535SBarry Smith
875f3fbd535SBarry Smith PetscFunctionBegin;
87628b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8771a97d7b6SStefano Zampini n = mglevels[0]->levels;
87801bc414fSDmitry Karpeev /* FIX: Move this to PCSetFromOptions_MG? */
8793aeaf226SBarry Smith if (mg->usedmfornumberoflevels) {
8803aeaf226SBarry Smith PetscInt levels;
881efba3485SBarry Smith
8829566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels));
8833aeaf226SBarry Smith levels++;
8843aeaf226SBarry Smith if (levels > n) { /* the problem is now being solved on a finer grid */
8859566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL));
8863aeaf226SBarry Smith n = levels;
8879566063dSJacob Faibussowitsch PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8883aeaf226SBarry Smith mglevels = mg->levels;
8893aeaf226SBarry Smith }
8903aeaf226SBarry Smith }
8913aeaf226SBarry Smith
892f3fbd535SBarry Smith /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
893f3fbd535SBarry Smith /* so use those from global PC */
894f3fbd535SBarry Smith /* Is this what we always want? What if user wants to keep old one? */
8959566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
89698e04984SBarry Smith if (opsset) {
89798e04984SBarry Smith Mat mmat;
8989566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
89998e04984SBarry Smith if (mmat == pc->pmat) opsset = PETSC_FALSE;
90098e04984SBarry Smith }
901bbbcb081SMark Adams /* fine grid smoother inherits the reuse-pc flag */
902bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[n - 1]->smoothd, &cpc));
903bbbcb081SMark Adams cpc->reusepreconditioner = pc->reusepreconditioner;
904bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[n - 1]->smoothu, &cpc));
905bbbcb081SMark Adams cpc->reusepreconditioner = pc->reusepreconditioner;
9064a5f07a5SMark F. Adams
90741b6fd38SMatthew G. Knepley /* Create CR solvers */
9089566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptCR(pc, &doCR));
90941b6fd38SMatthew G. Knepley if (doCR) {
91041b6fd38SMatthew G. Knepley const char *prefix;
91141b6fd38SMatthew G. Knepley
9129566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix));
91341b6fd38SMatthew G. Knepley for (i = 1; i < n; ++i) {
91441b6fd38SMatthew G. Knepley PC ipc, cr;
91541b6fd38SMatthew G. Knepley char crprefix[128];
91641b6fd38SMatthew G. Knepley
9179566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
9183821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
9199566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
9209566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
9219566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
9229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
9239566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9249566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9259566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9269566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
92741b6fd38SMatthew G. Knepley
9289566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCCOMPOSITE));
9299566063dSJacob Faibussowitsch PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9309566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9319566063dSJacob Faibussowitsch PetscCall(CreateCR_Private(pc, i, &cr));
9329566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPC(ipc, cr));
9339566063dSJacob Faibussowitsch PetscCall(PCDestroy(&cr));
93441b6fd38SMatthew G. Knepley
935fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
9369566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
937835f2295SStefano Zampini PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i));
9389566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
93941b6fd38SMatthew G. Knepley }
94041b6fd38SMatthew G. Knepley }
94141b6fd38SMatthew G. Knepley
9424a5f07a5SMark F. Adams if (!opsset) {
9439566063dSJacob Faibussowitsch PetscCall(PCGetUseAmat(pc, &use_amat));
9444a5f07a5SMark F. Adams if (use_amat) {
9459566063dSJacob 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"));
9469566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
94769858f1bSStefano Zampini } else {
9489566063dSJacob 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"));
9499566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9504a5f07a5SMark F. Adams }
9514a5f07a5SMark F. Adams }
952f3fbd535SBarry Smith
9539c7ffb39SBarry Smith for (i = n - 1; i > 0; i--) {
9549c7ffb39SBarry Smith if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9559c7ffb39SBarry Smith missinginterpolate = PETSC_TRUE;
9562b3cbbdaSStefano Zampini break;
9579c7ffb39SBarry Smith }
9589c7ffb39SBarry Smith }
9592134b1e4SBarry Smith
9609566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9612134b1e4SBarry Smith if (dA == dB) dAeqdB = PETSC_TRUE;
9623a7d0413SPierre Jolivet if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9632134b1e4SBarry Smith
9642b3cbbdaSStefano Zampini if (pc->dm && !pc->setupcalled) {
9652b3cbbdaSStefano Zampini /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9662b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
967*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, KSP_DMACTIVE_ALL, PETSC_FALSE));
9682b3cbbdaSStefano Zampini if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9692b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
970*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, KSP_DMACTIVE_ALL, PETSC_FALSE));
9712b3cbbdaSStefano Zampini }
9722b3cbbdaSStefano Zampini if (mglevels[n - 1]->cr) {
9732b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
974*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, KSP_DMACTIVE_ALL, PETSC_FALSE));
9752b3cbbdaSStefano Zampini }
9762b3cbbdaSStefano Zampini }
9772b3cbbdaSStefano Zampini
9789c7ffb39SBarry Smith /*
9799c7ffb39SBarry Smith Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9802b3cbbdaSStefano Zampini Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9819c7ffb39SBarry Smith */
98232fe681dSStefano Zampini if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
98332fe681dSStefano Zampini /* first see if we can compute a coarse space */
98432fe681dSStefano Zampini if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
98532fe681dSStefano Zampini for (i = n - 2; i > -1; i--) {
98632fe681dSStefano Zampini if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
98732fe681dSStefano Zampini PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
98832fe681dSStefano Zampini PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
98932fe681dSStefano Zampini }
99032fe681dSStefano Zampini }
99132fe681dSStefano Zampini } else { /* construct the interpolation from the DMs */
9922e499ae9SBarry Smith Mat p;
99373250ac0SBarry Smith Vec rscale;
99464da7896SBarry Smith
99564da7896SBarry Smith PetscCheck(n == 1 || pc->dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PC lacks a DM so cannot automatically construct a multigrid hierarchy. Number of levels requested %" PetscInt_FMT, n);
9969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &dms));
997218a07d4SBarry Smith dms[n - 1] = pc->dm;
998ef1267afSMatthew G. Knepley /* Separately create them so we do not get DMKSP interference between levels */
9999566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
1000218a07d4SBarry Smith for (i = n - 2; i > -1; i--) {
1001eab52d2bSLawrence Mitchell PetscBool dmhasrestrict, dmhasinject;
1002218e2965SBarry Smith
10039566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
1004*bf0c7fc2SBarry Smith if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, KSP_DMACTIVE_ALL, PETSC_FALSE));
1005*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[i]->smoothd, KSP_DMACTIVE_RHS, PETSC_FALSE));
1006c27ee7a3SPatrick Farrell if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
10079566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
1008*bf0c7fc2SBarry Smith if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, KSP_DMACTIVE_ALL, PETSC_FALSE));
1009*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[i]->smoothu, KSP_DMACTIVE_RHS, PETSC_FALSE));
1010c27ee7a3SPatrick Farrell }
101141b6fd38SMatthew G. Knepley if (mglevels[i]->cr) {
10129566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
1013*bf0c7fc2SBarry Smith if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, KSP_DMACTIVE_ALL, PETSC_FALSE));
1014*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(mglevels[i]->cr, KSP_DMACTIVE_RHS, PETSC_FALSE));
101541b6fd38SMatthew G. Knepley }
101624c3aa18SBarry Smith if (!mglevels[i + 1]->interpolate) {
10179566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
10189566063dSJacob Faibussowitsch PetscCall(PCMGSetInterpolation(pc, i + 1, p));
10199566063dSJacob Faibussowitsch if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
10209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rscale));
10219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p));
1022218a07d4SBarry Smith }
10239566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
10243ad4599aSBarry Smith if (dmhasrestrict && !mglevels[i + 1]->restrct) {
10259566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
10269566063dSJacob Faibussowitsch PetscCall(PCMGSetRestriction(pc, i + 1, p));
10279566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p));
10283ad4599aSBarry Smith }
10299566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
1030eab52d2bSLawrence Mitchell if (dmhasinject && !mglevels[i + 1]->inject) {
10319566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
10329566063dSJacob Faibussowitsch PetscCall(PCMGSetInjection(pc, i + 1, p));
10339566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p));
1034eab52d2bSLawrence Mitchell }
103524c3aa18SBarry Smith }
10362d2b81a6SBarry Smith
10379566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10389566063dSJacob Faibussowitsch PetscCall(PetscFree(dms));
1039ce4cda84SJed Brown }
104032fe681dSStefano Zampini }
1041cab2e9ccSBarry Smith
10422134b1e4SBarry Smith if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10432134b1e4SBarry Smith Mat A, B;
10442134b1e4SBarry Smith PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10452134b1e4SBarry Smith MatReuse reuse = MAT_INITIAL_MATRIX;
10462134b1e4SBarry Smith
10472b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10482b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10492134b1e4SBarry Smith if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1050f3fbd535SBarry Smith for (i = n - 2; i > -1; i--) {
10517827d75bSBarry 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");
105248a46eb9SPierre Jolivet if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
105348a46eb9SPierre Jolivet if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
105448a46eb9SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
105548a46eb9SPierre Jolivet if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
105648a46eb9SPierre Jolivet if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10572134b1e4SBarry Smith /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10582134b1e4SBarry Smith if (!doA && dAeqdB) {
10599566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10602134b1e4SBarry Smith A = B;
10612134b1e4SBarry Smith } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10629566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10639566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A));
1064b9367914SBarry Smith }
10652134b1e4SBarry Smith if (!doB && dAeqdB) {
10669566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10672134b1e4SBarry Smith B = A;
10682134b1e4SBarry Smith } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10699566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10709566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B));
10717d537d92SJed Brown }
10722134b1e4SBarry Smith if (reuse == MAT_INITIAL_MATRIX) {
10739566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10749566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)A));
10759566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)B));
10762134b1e4SBarry Smith }
10772134b1e4SBarry Smith dA = A;
1078f3fbd535SBarry Smith dB = B;
1079f3fbd535SBarry Smith }
1080f3fbd535SBarry Smith }
1081f3b08a26SMatthew G. Knepley
1082f3b08a26SMatthew G. Knepley /* Adapt interpolation matrices */
10832b3cbbdaSStefano Zampini if (adaptInterpolation) {
1084f3b08a26SMatthew G. Knepley for (i = 0; i < n; ++i) {
108548a46eb9SPierre Jolivet if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10862b3cbbdaSStefano Zampini if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1087f3b08a26SMatthew G. Knepley }
108848a46eb9SPierre Jolivet for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1089f3b08a26SMatthew G. Knepley }
1090f3b08a26SMatthew G. Knepley
10912134b1e4SBarry Smith if (needRestricts && pc->dm) {
1092caa4e7f2SJed Brown for (i = n - 2; i >= 0; i--) {
1093ccceb50cSJed Brown DM dmfine, dmcoarse;
1094caa4e7f2SJed Brown Mat Restrict, Inject;
1095caa4e7f2SJed Brown Vec rscale;
1096218e2965SBarry Smith
10979566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10989566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10999566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
11009566063dSJacob Faibussowitsch PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
11019566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
11029566063dSJacob Faibussowitsch PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1103caa4e7f2SJed Brown }
1104caa4e7f2SJed Brown }
1105f3fbd535SBarry Smith
1106f3fbd535SBarry Smith if (!pc->setupcalled) {
110748a46eb9SPierre Jolivet for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1108f3fbd535SBarry Smith for (i = 1; i < n; i++) {
110948a46eb9SPierre Jolivet if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
111048a46eb9SPierre Jolivet if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1111f3fbd535SBarry Smith }
111215229ffcSPierre Jolivet /* insure that if either interpolation or restriction is set the other one is set */
1113f3fbd535SBarry Smith for (i = 1; i < n; i++) {
11149566063dSJacob Faibussowitsch PetscCall(PCMGGetInterpolation(pc, i, NULL));
11159566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i, NULL));
1116f3fbd535SBarry Smith }
1117f3fbd535SBarry Smith for (i = 0; i < n - 1; i++) {
1118f3fbd535SBarry Smith if (!mglevels[i]->b) {
1119f3fbd535SBarry Smith Vec *vec;
11209566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
11219566063dSJacob Faibussowitsch PetscCall(PCMGSetRhs(pc, i, *vec));
11229566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec));
11239566063dSJacob Faibussowitsch PetscCall(PetscFree(vec));
1124f3fbd535SBarry Smith }
1125f3fbd535SBarry Smith if (!mglevels[i]->r && i) {
11269566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11279566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, i, tvec));
11289566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec));
1129f3fbd535SBarry Smith }
1130f3fbd535SBarry Smith if (!mglevels[i]->x) {
11319566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11329566063dSJacob Faibussowitsch PetscCall(PCMGSetX(pc, i, tvec));
11339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec));
1134f3fbd535SBarry Smith }
113541b6fd38SMatthew G. Knepley if (doCR) {
11369566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11379566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11389566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[i]->crb));
113941b6fd38SMatthew G. Knepley }
1140f3fbd535SBarry Smith }
1141f3fbd535SBarry Smith if (n != 1 && !mglevels[n - 1]->r) {
1142f3fbd535SBarry Smith /* PCMGSetR() on the finest level if user did not supply it */
1143f3fbd535SBarry Smith Vec *vec;
1144218e2965SBarry Smith
11459566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11469566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, n - 1, *vec));
11479566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec));
11489566063dSJacob Faibussowitsch PetscCall(PetscFree(vec));
1149f3fbd535SBarry Smith }
115041b6fd38SMatthew G. Knepley if (doCR) {
11519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11529566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11539566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
115441b6fd38SMatthew G. Knepley }
1155f3fbd535SBarry Smith }
1156f3fbd535SBarry Smith
115798e04984SBarry Smith if (pc->dm) {
115898e04984SBarry Smith /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
115998e04984SBarry Smith for (i = 0; i < n - 1; i++) {
116098e04984SBarry Smith if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
116198e04984SBarry Smith }
116298e04984SBarry Smith }
116308549ed4SJed Brown // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
116408549ed4SJed Brown // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
116508549ed4SJed Brown if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1166f3fbd535SBarry Smith
1167f3fbd535SBarry Smith for (i = 1; i < n; i++) {
11682a21e185SBarry Smith if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1169f3fbd535SBarry Smith /* if doing only down then initial guess is zero */
11709566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1171f3fbd535SBarry Smith }
11729566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11739566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11749566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothd));
1175d4645a75SStefano Zampini if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11769566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1177d42688cbSBarry Smith if (!mglevels[i]->residual) {
1178d42688cbSBarry Smith Mat mat;
1179218e2965SBarry Smith
11809566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11819566063dSJacob Faibussowitsch PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1182d42688cbSBarry Smith }
1183fcb023d4SJed Brown if (!mglevels[i]->residualtranspose) {
1184fcb023d4SJed Brown Mat mat;
1185218e2965SBarry Smith
11869566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11879566063dSJacob Faibussowitsch PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1188fcb023d4SJed Brown }
1189f3fbd535SBarry Smith }
1190f3fbd535SBarry Smith for (i = 1; i < n; i++) {
1191f3fbd535SBarry Smith if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1192f3fbd535SBarry Smith Mat downmat, downpmat;
1193f3fbd535SBarry Smith
1194f3fbd535SBarry Smith /* check if operators have been set for up, if not use down operators to set them */
11959566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1196f3fbd535SBarry Smith if (!opsset) {
11979566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11989566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1199f3fbd535SBarry Smith }
1200f3fbd535SBarry Smith
12019566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
12029566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
12039566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothu));
1204d4645a75SStefano Zampini if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
12059566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1206f3fbd535SBarry Smith }
120741b6fd38SMatthew G. Knepley if (mglevels[i]->cr) {
120841b6fd38SMatthew G. Knepley Mat downmat, downpmat;
120941b6fd38SMatthew G. Knepley
121041b6fd38SMatthew G. Knepley /* check if operators have been set for up, if not use down operators to set them */
12119566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
121241b6fd38SMatthew G. Knepley if (!opsset) {
12139566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
12149566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
121541b6fd38SMatthew G. Knepley }
121641b6fd38SMatthew G. Knepley
12179566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
12189566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
12199566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->cr));
1220d4645a75SStefano Zampini if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
12219566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
122241b6fd38SMatthew G. Knepley }
1223f3fbd535SBarry Smith }
1224f3fbd535SBarry Smith
12259566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
12269566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[0]->smoothd));
1227d4645a75SStefano Zampini if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
12289566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1229f3fbd535SBarry Smith
1230f3fbd535SBarry Smith /*
1231f3fbd535SBarry Smith Dump the interpolation/restriction matrices plus the
1232e3c5b3baSBarry Smith Jacobian/stiffness on each level. This allows MATLAB users to
1233f3fbd535SBarry Smith easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1234f3fbd535SBarry Smith
1235f3fbd535SBarry Smith Only support one or the other at the same time.
1236f3fbd535SBarry Smith */
1237f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12389566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1239ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1240f3fbd535SBarry Smith dump = PETSC_FALSE;
1241f3fbd535SBarry Smith #endif
12429566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1243ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1244f3fbd535SBarry Smith
1245f3fbd535SBarry Smith if (viewer) {
124648a46eb9SPierre Jolivet for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1247f3fbd535SBarry Smith for (i = 0; i < n; i++) {
12489566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12499566063dSJacob Faibussowitsch PetscCall(MatView(pc->mat, viewer));
1250f3fbd535SBarry Smith }
1251f3fbd535SBarry Smith }
12523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1253f3fbd535SBarry Smith }
1254f3fbd535SBarry Smith
PCMGGetLevels_MG(PC pc,PetscInt * levels)1255d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1256d71ae5a4SJacob Faibussowitsch {
125797d33e41SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data;
125897d33e41SMatthew G. Knepley
125997d33e41SMatthew G. Knepley PetscFunctionBegin;
126097d33e41SMatthew G. Knepley *levels = mg->nlevels;
12613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
126297d33e41SMatthew G. Knepley }
126397d33e41SMatthew G. Knepley
12644b9ad928SBarry Smith /*@
1265f1580f4eSBarry Smith PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12664b9ad928SBarry Smith
12674b9ad928SBarry Smith Not Collective
12684b9ad928SBarry Smith
12694b9ad928SBarry Smith Input Parameter:
12704b9ad928SBarry Smith . pc - the preconditioner context
12714b9ad928SBarry Smith
1272feefa0e1SJacob Faibussowitsch Output Parameter:
12734b9ad928SBarry Smith . levels - the number of levels
12744b9ad928SBarry Smith
12754b9ad928SBarry Smith Level: advanced
12764b9ad928SBarry Smith
1277562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()`
12784b9ad928SBarry Smith @*/
PCMGGetLevels(PC pc,PetscInt * levels)1279d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1280d71ae5a4SJacob Faibussowitsch {
12814b9ad928SBarry Smith PetscFunctionBegin;
12820700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12834f572ea9SToby Isaac PetscAssertPointer(levels, 2);
128497d33e41SMatthew G. Knepley *levels = 0;
1285cac4c232SBarry Smith PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
12874b9ad928SBarry Smith }
12884b9ad928SBarry Smith
12894b9ad928SBarry Smith /*@
1290f1580f4eSBarry Smith PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1291e7d4b4cbSMark Adams
1292e7d4b4cbSMark Adams Input Parameter:
1293e7d4b4cbSMark Adams . pc - the preconditioner context
1294e7d4b4cbSMark Adams
129590db8557SMark Adams Output Parameters:
129690db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
129790db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1298e7d4b4cbSMark Adams
1299e7d4b4cbSMark Adams Level: advanced
1300e7d4b4cbSMark Adams
1301f1580f4eSBarry Smith Note:
1302f1580f4eSBarry Smith This is often call the operator complexity in multigrid literature
1303f1580f4eSBarry Smith
1304562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1305e7d4b4cbSMark Adams @*/
PCMGGetGridComplexity(PC pc,PetscReal * gc,PetscReal * oc)1306d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1307d71ae5a4SJacob Faibussowitsch {
1308e7d4b4cbSMark Adams PC_MG *mg = (PC_MG *)pc->data;
1309e7d4b4cbSMark Adams PC_MG_Levels **mglevels = mg->levels;
1310e7d4b4cbSMark Adams PetscInt lev, N;
1311e7d4b4cbSMark Adams PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1312e7d4b4cbSMark Adams MatInfo info;
1313e7d4b4cbSMark Adams
1314e7d4b4cbSMark Adams PetscFunctionBegin;
131590db8557SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
13164f572ea9SToby Isaac if (gc) PetscAssertPointer(gc, 2);
13174f572ea9SToby Isaac if (oc) PetscAssertPointer(oc, 3);
1318e7d4b4cbSMark Adams if (!pc->setupcalled) {
131990db8557SMark Adams if (gc) *gc = 0;
132090db8557SMark Adams if (oc) *oc = 0;
13213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1322e7d4b4cbSMark Adams }
1323e7d4b4cbSMark Adams PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1324e7d4b4cbSMark Adams for (lev = 0; lev < mg->nlevels; lev++) {
1325e7d4b4cbSMark Adams Mat dB;
13269566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
13279566063dSJacob Faibussowitsch PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
13289566063dSJacob Faibussowitsch PetscCall(MatGetSize(dB, &N, NULL));
1329e7d4b4cbSMark Adams sgc += N;
1330e7d4b4cbSMark Adams soc += info.nz_used;
13319371c9d4SSatish Balay if (lev == mg->nlevels - 1) {
13329371c9d4SSatish Balay nnz0 = info.nz_used;
13339371c9d4SSatish Balay n0 = N;
13349371c9d4SSatish Balay }
1335e7d4b4cbSMark Adams }
13360fdf79fbSJacob Faibussowitsch PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13370fdf79fbSJacob Faibussowitsch *gc = (PetscReal)(sgc / n0);
133890db8557SMark Adams if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1340e7d4b4cbSMark Adams }
1341e7d4b4cbSMark Adams
1342e7d4b4cbSMark Adams /*@
134304c3f3b8SBarry Smith PCMGSetType - Determines the form of multigrid to use, either
13444b9ad928SBarry Smith multiplicative, additive, full, or the Kaskade algorithm.
13454b9ad928SBarry Smith
1346c3339decSBarry Smith Logically Collective
13474b9ad928SBarry Smith
13484b9ad928SBarry Smith Input Parameters:
13494b9ad928SBarry Smith + pc - the preconditioner context
1350f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13514b9ad928SBarry Smith
13524b9ad928SBarry Smith Options Database Key:
135320f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13544b9ad928SBarry Smith
13554b9ad928SBarry Smith Level: advanced
13564b9ad928SBarry Smith
1357562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13584b9ad928SBarry Smith @*/
PCMGSetType(PC pc,PCMGType form)1359d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1360d71ae5a4SJacob Faibussowitsch {
1361f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
13624b9ad928SBarry Smith
13634b9ad928SBarry Smith PetscFunctionBegin;
13640700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1365c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc, form, 2);
136631567311SBarry Smith mg->am = form;
13679dcbbd2bSBarry Smith if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1368c60c7ad4SBarry Smith else pc->ops->applyrichardson = NULL;
13693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1370c60c7ad4SBarry Smith }
1371c60c7ad4SBarry Smith
1372c60c7ad4SBarry Smith /*@
1373f1580f4eSBarry Smith PCMGGetType - Finds the form of multigrid the `PCMG` is using multiplicative, additive, full, or the Kaskade algorithm.
1374c60c7ad4SBarry Smith
1375c3339decSBarry Smith Logically Collective
1376c60c7ad4SBarry Smith
1377c60c7ad4SBarry Smith Input Parameter:
1378c60c7ad4SBarry Smith . pc - the preconditioner context
1379c60c7ad4SBarry Smith
1380c60c7ad4SBarry Smith Output Parameter:
1381f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1382c60c7ad4SBarry Smith
1383c60c7ad4SBarry Smith Level: advanced
1384c60c7ad4SBarry Smith
1385562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1386c60c7ad4SBarry Smith @*/
PCMGGetType(PC pc,PCMGType * type)1387d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1388d71ae5a4SJacob Faibussowitsch {
1389c60c7ad4SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
1390c60c7ad4SBarry Smith
1391c60c7ad4SBarry Smith PetscFunctionBegin;
1392c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1393c60c7ad4SBarry Smith *type = mg->am;
13943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
13954b9ad928SBarry Smith }
13964b9ad928SBarry Smith
13974b9ad928SBarry Smith /*@
1398f1580f4eSBarry Smith PCMGSetCycleType - Sets the type cycles to use. Use `PCMGSetCycleTypeOnLevel()` for more
13994b9ad928SBarry Smith complicated cycling.
14004b9ad928SBarry Smith
1401c3339decSBarry Smith Logically Collective
14024b9ad928SBarry Smith
14034b9ad928SBarry Smith Input Parameters:
1404c2be2410SBarry Smith + pc - the multigrid context
1405f1580f4eSBarry Smith - n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
14064b9ad928SBarry Smith
14074b9ad928SBarry Smith Options Database Key:
1408c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
14094b9ad928SBarry Smith
14104b9ad928SBarry Smith Level: advanced
14114b9ad928SBarry Smith
1412562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
14134b9ad928SBarry Smith @*/
PCMGSetCycleType(PC pc,PCMGCycleType n)1414d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1415d71ae5a4SJacob Faibussowitsch {
1416f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
1417f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels;
141879416396SBarry Smith PetscInt i, levels;
14194b9ad928SBarry Smith
14204b9ad928SBarry Smith PetscFunctionBegin;
14210700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
142269fbec6eSBarry Smith PetscValidLogicalCollectiveEnum(pc, n, 2);
142328b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1424f3fbd535SBarry Smith levels = mglevels[0]->levels;
14252fa5cd67SKarl Rupp for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
14263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
14274b9ad928SBarry Smith }
14284b9ad928SBarry Smith
14298cc2d5dfSBarry Smith /*@
14308cc2d5dfSBarry Smith PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1431f1580f4eSBarry Smith of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
14328cc2d5dfSBarry Smith
1433c3339decSBarry Smith Logically Collective
14348cc2d5dfSBarry Smith
14358cc2d5dfSBarry Smith Input Parameters:
14368cc2d5dfSBarry Smith + pc - the multigrid context
14378cc2d5dfSBarry Smith - n - number of cycles (default is 1)
14388cc2d5dfSBarry Smith
14398cc2d5dfSBarry Smith Options Database Key:
1440147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14418cc2d5dfSBarry Smith
14428cc2d5dfSBarry Smith Level: advanced
14438cc2d5dfSBarry Smith
1444f1580f4eSBarry Smith Note:
1445f1580f4eSBarry Smith This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14468cc2d5dfSBarry Smith
1447562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14488cc2d5dfSBarry Smith @*/
PCMGMultiplicativeSetCycles(PC pc,PetscInt n)1449d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1450d71ae5a4SJacob Faibussowitsch {
1451f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
14528cc2d5dfSBarry Smith
14538cc2d5dfSBarry Smith PetscFunctionBegin;
14540700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1455c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2);
14562a21e185SBarry Smith mg->cyclesperpcapply = n;
14573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
14588cc2d5dfSBarry Smith }
14598cc2d5dfSBarry Smith
1460bbbcb081SMark Adams /*
1461bbbcb081SMark Adams Since the finest level KSP shares the original matrix (of the entire system), it's preconditioner
1462bbbcb081SMark Adams should not be updated if the whole PC is supposed to reuse the preconditioner
1463bbbcb081SMark Adams */
PCSetReusePreconditioner_MG(PC pc,PetscBool flag)1464bbbcb081SMark Adams static PetscErrorCode PCSetReusePreconditioner_MG(PC pc, PetscBool flag)
1465bbbcb081SMark Adams {
1466bbbcb081SMark Adams PC_MG *mg = (PC_MG *)pc->data;
1467bbbcb081SMark Adams PC_MG_Levels **mglevels = mg->levels;
1468bbbcb081SMark Adams PetscInt levels;
1469bbbcb081SMark Adams PC tpc;
1470bbbcb081SMark Adams
1471bbbcb081SMark Adams PetscFunctionBegin;
1472bbbcb081SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1473bbbcb081SMark Adams PetscValidLogicalCollectiveBool(pc, flag, 2);
1474bbbcb081SMark Adams if (mglevels) {
1475bbbcb081SMark Adams levels = mglevels[0]->levels;
1476bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1477bbbcb081SMark Adams tpc->reusepreconditioner = flag;
1478bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1479bbbcb081SMark Adams tpc->reusepreconditioner = flag;
1480bbbcb081SMark Adams }
1481bbbcb081SMark Adams PetscFunctionReturn(PETSC_SUCCESS);
1482bbbcb081SMark Adams }
1483bbbcb081SMark Adams
PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use)148466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1485d71ae5a4SJacob Faibussowitsch {
1486fb15c04eSBarry Smith PC_MG *mg = (PC_MG *)pc->data;
1487fb15c04eSBarry Smith
1488fb15c04eSBarry Smith PetscFunctionBegin;
14892134b1e4SBarry Smith mg->galerkin = use;
14903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1491fb15c04eSBarry Smith }
1492fb15c04eSBarry Smith
1493c2be2410SBarry Smith /*@
149497177400SBarry Smith PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
149582b87d87SMatthew G. Knepley finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1496c2be2410SBarry Smith
1497c3339decSBarry Smith Logically Collective
1498c2be2410SBarry Smith
1499c2be2410SBarry Smith Input Parameters:
1500c91913d3SJed Brown + pc - the multigrid context
1501f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1502c2be2410SBarry Smith
1503c2be2410SBarry Smith Options Database Key:
1504147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1505c2be2410SBarry Smith
1506c2be2410SBarry Smith Level: intermediate
1507c2be2410SBarry Smith
1508f1580f4eSBarry Smith Note:
1509f1580f4eSBarry Smith Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1510f1580f4eSBarry Smith use the `PCMG` construction of the coarser grids.
15111c1aac46SBarry Smith
1512562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1513c2be2410SBarry Smith @*/
PCMGSetGalerkin(PC pc,PCMGGalerkinType use)1514d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1515d71ae5a4SJacob Faibussowitsch {
1516c2be2410SBarry Smith PetscFunctionBegin;
15170700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1518cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
15193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1520c2be2410SBarry Smith }
1521c2be2410SBarry Smith
15223fc8bf9cSBarry Smith /*@
1523f1580f4eSBarry Smith PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
15243fc8bf9cSBarry Smith
15253fc8bf9cSBarry Smith Not Collective
15263fc8bf9cSBarry Smith
15273fc8bf9cSBarry Smith Input Parameter:
15283fc8bf9cSBarry Smith . pc - the multigrid context
15293fc8bf9cSBarry Smith
15303fc8bf9cSBarry Smith Output Parameter:
1531f1580f4eSBarry 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`
15323fc8bf9cSBarry Smith
15333fc8bf9cSBarry Smith Level: intermediate
15343fc8bf9cSBarry Smith
1535562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
15363fc8bf9cSBarry Smith @*/
PCMGGetGalerkin(PC pc,PCMGGalerkinType * galerkin)1537d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1538d71ae5a4SJacob Faibussowitsch {
1539f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data;
15403fc8bf9cSBarry Smith
15413fc8bf9cSBarry Smith PetscFunctionBegin;
15420700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15432134b1e4SBarry Smith *galerkin = mg->galerkin;
15443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
15453fc8bf9cSBarry Smith }
15463fc8bf9cSBarry Smith
PCMGSetAdaptInterpolation_MG(PC pc,PetscBool adapt)154766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1548d71ae5a4SJacob Faibussowitsch {
1549f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data;
1550f3b08a26SMatthew G. Knepley
1551f3b08a26SMatthew G. Knepley PetscFunctionBegin;
1552f3b08a26SMatthew G. Knepley mg->adaptInterpolation = adapt;
15533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1554f3b08a26SMatthew G. Knepley }
1555f3b08a26SMatthew G. Knepley
PCMGGetAdaptInterpolation_MG(PC pc,PetscBool * adapt)155666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1557d71ae5a4SJacob Faibussowitsch {
1558f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data;
1559f3b08a26SMatthew G. Knepley
1560f3b08a26SMatthew G. Knepley PetscFunctionBegin;
1561f3b08a26SMatthew G. Knepley *adapt = mg->adaptInterpolation;
15623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1563f3b08a26SMatthew G. Knepley }
1564f3b08a26SMatthew G. Knepley
PCMGSetAdaptCoarseSpaceType_MG(PC pc,PCMGCoarseSpaceType ctype)156566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1566d71ae5a4SJacob Faibussowitsch {
15672b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data;
15682b3cbbdaSStefano Zampini
15692b3cbbdaSStefano Zampini PetscFunctionBegin;
15702b3cbbdaSStefano Zampini mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15712b3cbbdaSStefano Zampini mg->coarseSpaceType = ctype;
1572a077d33dSBarry Smith PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
15733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
15742b3cbbdaSStefano Zampini }
15752b3cbbdaSStefano Zampini
PCMGGetAdaptCoarseSpaceType_MG(PC pc,PCMGCoarseSpaceType * ctype)157666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1577d71ae5a4SJacob Faibussowitsch {
15782b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data;
15792b3cbbdaSStefano Zampini
15802b3cbbdaSStefano Zampini PetscFunctionBegin;
15812b3cbbdaSStefano Zampini *ctype = mg->coarseSpaceType;
15823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
15832b3cbbdaSStefano Zampini }
15842b3cbbdaSStefano Zampini
PCMGSetAdaptCR_MG(PC pc,PetscBool cr)158566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1586d71ae5a4SJacob Faibussowitsch {
158741b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data;
158841b6fd38SMatthew G. Knepley
158941b6fd38SMatthew G. Knepley PetscFunctionBegin;
159041b6fd38SMatthew G. Knepley mg->compatibleRelaxation = cr;
15913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
159241b6fd38SMatthew G. Knepley }
159341b6fd38SMatthew G. Knepley
PCMGGetAdaptCR_MG(PC pc,PetscBool * cr)159466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1595d71ae5a4SJacob Faibussowitsch {
159641b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data;
159741b6fd38SMatthew G. Knepley
159841b6fd38SMatthew G. Knepley PetscFunctionBegin;
159941b6fd38SMatthew G. Knepley *cr = mg->compatibleRelaxation;
16003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
160141b6fd38SMatthew G. Knepley }
160241b6fd38SMatthew G. Knepley
1603cc4c1da9SBarry Smith /*@
16042b3cbbdaSStefano Zampini PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
16052b3cbbdaSStefano Zampini
16062b3cbbdaSStefano 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.
16072b3cbbdaSStefano Zampini
1608c3339decSBarry Smith Logically Collective
16092b3cbbdaSStefano Zampini
16102b3cbbdaSStefano Zampini Input Parameters:
16112b3cbbdaSStefano Zampini + pc - the multigrid context
16122b3cbbdaSStefano Zampini - ctype - the type of coarse space
16132b3cbbdaSStefano Zampini
16142b3cbbdaSStefano Zampini Options Database Keys:
16152b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int> - The number of modes to use
1616a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw`
16172b3cbbdaSStefano Zampini
16182b3cbbdaSStefano Zampini Level: intermediate
16192b3cbbdaSStefano Zampini
1620a077d33dSBarry Smith Note:
1621a077d33dSBarry Smith Requires a `DM` with specific functionality be attached to the `PC`.
1622a077d33dSBarry Smith
1623a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM`
16242b3cbbdaSStefano Zampini @*/
PCMGSetAdaptCoarseSpaceType(PC pc,PCMGCoarseSpaceType ctype)1625d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1626d71ae5a4SJacob Faibussowitsch {
16272b3cbbdaSStefano Zampini PetscFunctionBegin;
16282b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16292b3cbbdaSStefano Zampini PetscValidLogicalCollectiveEnum(pc, ctype, 2);
16302b3cbbdaSStefano Zampini PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
16313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
16322b3cbbdaSStefano Zampini }
16332b3cbbdaSStefano Zampini
1634cc4c1da9SBarry Smith /*@
16352b3cbbdaSStefano Zampini PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
16362b3cbbdaSStefano Zampini
16372b3cbbdaSStefano Zampini Not Collective
16382b3cbbdaSStefano Zampini
16392b3cbbdaSStefano Zampini Input Parameter:
16402b3cbbdaSStefano Zampini . pc - the multigrid context
16412b3cbbdaSStefano Zampini
16422b3cbbdaSStefano Zampini Output Parameter:
16432b3cbbdaSStefano Zampini . ctype - the type of coarse space
16442b3cbbdaSStefano Zampini
16452b3cbbdaSStefano Zampini Level: intermediate
16462b3cbbdaSStefano Zampini
1647562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
16482b3cbbdaSStefano Zampini @*/
PCMGGetAdaptCoarseSpaceType(PC pc,PCMGCoarseSpaceType * ctype)1649d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1650d71ae5a4SJacob Faibussowitsch {
16512b3cbbdaSStefano Zampini PetscFunctionBegin;
16522b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16534f572ea9SToby Isaac PetscAssertPointer(ctype, 2);
16542b3cbbdaSStefano Zampini PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
16553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
16562b3cbbdaSStefano Zampini }
16572b3cbbdaSStefano Zampini
16582b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1659f3b08a26SMatthew G. Knepley /*@
1660f3b08a26SMatthew 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.
1661f3b08a26SMatthew G. Knepley
1662c3339decSBarry Smith Logically Collective
1663f3b08a26SMatthew G. Knepley
1664f3b08a26SMatthew G. Knepley Input Parameters:
1665f3b08a26SMatthew G. Knepley + pc - the multigrid context
1666f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1667f3b08a26SMatthew G. Knepley
1668f3b08a26SMatthew G. Knepley Options Database Keys:
1669f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp - Turn on adaptation
1670f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension
1671f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1672f3b08a26SMatthew G. Knepley
1673f3b08a26SMatthew G. Knepley Level: intermediate
1674f3b08a26SMatthew G. Knepley
1675562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1676f3b08a26SMatthew G. Knepley @*/
PCMGSetAdaptInterpolation(PC pc,PetscBool adapt)1677d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1678d71ae5a4SJacob Faibussowitsch {
1679f3b08a26SMatthew G. Knepley PetscFunctionBegin;
1680f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1681cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1683f3b08a26SMatthew G. Knepley }
1684f3b08a26SMatthew G. Knepley
1685f3b08a26SMatthew G. Knepley /*@
1686f1580f4eSBarry Smith PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1687f1580f4eSBarry Smith and thus accurately interpolated.
1688f3b08a26SMatthew G. Knepley
168920f4b53cSBarry Smith Not Collective
1690f3b08a26SMatthew G. Knepley
1691f3b08a26SMatthew G. Knepley Input Parameter:
1692f3b08a26SMatthew G. Knepley . pc - the multigrid context
1693f3b08a26SMatthew G. Knepley
1694f3b08a26SMatthew G. Knepley Output Parameter:
1695f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1696f3b08a26SMatthew G. Knepley
1697f3b08a26SMatthew G. Knepley Level: intermediate
1698f3b08a26SMatthew G. Knepley
1699562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1700f3b08a26SMatthew G. Knepley @*/
PCMGGetAdaptInterpolation(PC pc,PetscBool * adapt)1701d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1702d71ae5a4SJacob Faibussowitsch {
1703f3b08a26SMatthew G. Knepley PetscFunctionBegin;
1704f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17054f572ea9SToby Isaac PetscAssertPointer(adapt, 2);
1706cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
17073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1708f3b08a26SMatthew G. Knepley }
1709f3b08a26SMatthew G. Knepley
17104b9ad928SBarry Smith /*@
171141b6fd38SMatthew G. Knepley PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
171241b6fd38SMatthew G. Knepley
1713c3339decSBarry Smith Logically Collective
171441b6fd38SMatthew G. Knepley
171541b6fd38SMatthew G. Knepley Input Parameters:
171641b6fd38SMatthew G. Knepley + pc - the multigrid context
171741b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
171841b6fd38SMatthew G. Knepley
1719f1580f4eSBarry Smith Options Database Key:
172041b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
172141b6fd38SMatthew G. Knepley
172241b6fd38SMatthew G. Knepley Level: intermediate
172341b6fd38SMatthew G. Knepley
1724562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
172541b6fd38SMatthew G. Knepley @*/
PCMGSetAdaptCR(PC pc,PetscBool cr)1726d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1727d71ae5a4SJacob Faibussowitsch {
172841b6fd38SMatthew G. Knepley PetscFunctionBegin;
172941b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1730cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
17313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
173241b6fd38SMatthew G. Knepley }
173341b6fd38SMatthew G. Knepley
173441b6fd38SMatthew G. Knepley /*@
173541b6fd38SMatthew G. Knepley PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
173641b6fd38SMatthew G. Knepley
173720f4b53cSBarry Smith Not Collective
173841b6fd38SMatthew G. Knepley
173941b6fd38SMatthew G. Knepley Input Parameter:
174041b6fd38SMatthew G. Knepley . pc - the multigrid context
174141b6fd38SMatthew G. Knepley
174241b6fd38SMatthew G. Knepley Output Parameter:
174341b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
174441b6fd38SMatthew G. Knepley
174541b6fd38SMatthew G. Knepley Level: intermediate
174641b6fd38SMatthew G. Knepley
1747562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
174841b6fd38SMatthew G. Knepley @*/
PCMGGetAdaptCR(PC pc,PetscBool * cr)1749d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1750d71ae5a4SJacob Faibussowitsch {
175141b6fd38SMatthew G. Knepley PetscFunctionBegin;
175241b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17534f572ea9SToby Isaac PetscAssertPointer(cr, 2);
1754cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
17553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
175641b6fd38SMatthew G. Knepley }
175741b6fd38SMatthew G. Knepley
175841b6fd38SMatthew G. Knepley /*@
175906792cafSBarry Smith PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1760f1580f4eSBarry Smith on all levels. Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1761710315b6SLawrence Mitchell pre- and post-smoothing steps.
176206792cafSBarry Smith
1763c3339decSBarry Smith Logically Collective
176406792cafSBarry Smith
176506792cafSBarry Smith Input Parameters:
1766feefa0e1SJacob Faibussowitsch + pc - the multigrid context
176706792cafSBarry Smith - n - the number of smoothing steps
176806792cafSBarry Smith
176906792cafSBarry Smith Options Database Key:
1770a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
177106792cafSBarry Smith
177206792cafSBarry Smith Level: advanced
177306792cafSBarry 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.
177606792cafSBarry Smith
1777562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()`
177806792cafSBarry Smith @*/
PCMGSetNumberSmooth(PC pc,PetscInt n)1779d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1780d71ae5a4SJacob Faibussowitsch {
178106792cafSBarry Smith PC_MG *mg = (PC_MG *)pc->data;
178206792cafSBarry Smith PC_MG_Levels **mglevels = mg->levels;
178306792cafSBarry Smith PetscInt i, levels;
178406792cafSBarry Smith
178506792cafSBarry Smith PetscFunctionBegin;
178606792cafSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
178706792cafSBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2);
178828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
178906792cafSBarry Smith levels = mglevels[0]->levels;
179006792cafSBarry Smith
179106792cafSBarry Smith for (i = 1; i < levels; i++) {
1792fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
1793fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
179406792cafSBarry Smith mg->default_smoothu = n;
179506792cafSBarry Smith mg->default_smoothd = n;
179606792cafSBarry Smith }
17973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
179806792cafSBarry Smith }
179906792cafSBarry Smith
1800f442ab6aSBarry Smith /*@
1801f1580f4eSBarry Smith PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1802710315b6SLawrence Mitchell and adds the suffix _up to the options name
1803f442ab6aSBarry Smith
1804c3339decSBarry Smith Logically Collective
1805f442ab6aSBarry Smith
1806f1580f4eSBarry Smith Input Parameter:
1807f442ab6aSBarry Smith . pc - the preconditioner context
1808f442ab6aSBarry Smith
1809f442ab6aSBarry Smith Options Database Key:
1810147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1811f442ab6aSBarry Smith
1812f442ab6aSBarry Smith Level: advanced
1813f442ab6aSBarry Smith
1814f1580f4eSBarry Smith Note:
1815f1580f4eSBarry 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.
1816f442ab6aSBarry Smith
1817562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()`
1818f442ab6aSBarry Smith @*/
PCMGSetDistinctSmoothUp(PC pc)1819d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1820d71ae5a4SJacob Faibussowitsch {
1821f442ab6aSBarry Smith PC_MG *mg = (PC_MG *)pc->data;
1822f442ab6aSBarry Smith PC_MG_Levels **mglevels = mg->levels;
1823f442ab6aSBarry Smith PetscInt i, levels;
1824f442ab6aSBarry Smith KSP subksp;
1825f442ab6aSBarry Smith
1826f442ab6aSBarry Smith PetscFunctionBegin;
1827f442ab6aSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
182828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1829f442ab6aSBarry Smith levels = mglevels[0]->levels;
1830f442ab6aSBarry Smith
1831f442ab6aSBarry Smith for (i = 1; i < levels; i++) {
1832710315b6SLawrence Mitchell const char *prefix = NULL;
1833f442ab6aSBarry Smith /* make sure smoother up and down are different */
18349566063dSJacob Faibussowitsch PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
18359566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
18369566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(subksp, prefix));
18379566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1838f442ab6aSBarry Smith }
18393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1840f442ab6aSBarry Smith }
1841f442ab6aSBarry Smith
184207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
PCGetInterpolations_MG(PC pc,PetscInt * num_levels,Mat * interpolations[])184366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1844d71ae5a4SJacob Faibussowitsch {
184507a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data;
184607a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels;
184707a4832bSFande Kong Mat *mat;
184807a4832bSFande Kong PetscInt l;
184907a4832bSFande Kong
185007a4832bSFande Kong PetscFunctionBegin;
185128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat));
185307a4832bSFande Kong for (l = 1; l < mg->nlevels; l++) {
185407a4832bSFande Kong mat[l - 1] = mglevels[l]->interpolate;
18559566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
185607a4832bSFande Kong }
185707a4832bSFande Kong *num_levels = mg->nlevels;
185807a4832bSFande Kong *interpolations = mat;
18593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
186007a4832bSFande Kong }
186107a4832bSFande Kong
186207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
PCGetCoarseOperators_MG(PC pc,PetscInt * num_levels,Mat * coarseOperators[])186366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1864d71ae5a4SJacob Faibussowitsch {
186507a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data;
186607a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels;
186707a4832bSFande Kong PetscInt l;
186807a4832bSFande Kong Mat *mat;
186907a4832bSFande Kong
187007a4832bSFande Kong PetscFunctionBegin;
187128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat));
187307a4832bSFande Kong for (l = 0; l < mg->nlevels - 1; l++) {
1874f4f49eeaSPierre Jolivet PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l]));
18759566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l]));
187607a4832bSFande Kong }
187707a4832bSFande Kong *num_levels = mg->nlevels;
187807a4832bSFande Kong *coarseOperators = mat;
18793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
188007a4832bSFande Kong }
188107a4832bSFande Kong
1882f3b08a26SMatthew G. Knepley /*@C
1883f1580f4eSBarry Smith PCMGRegisterCoarseSpaceConstructor - Adds a method to the `PCMG` package for coarse space construction.
1884f3b08a26SMatthew G. Knepley
1885cc4c1da9SBarry Smith Not Collective, No Fortran Support
1886f3b08a26SMatthew G. Knepley
1887f3b08a26SMatthew G. Knepley Input Parameters:
1888f3b08a26SMatthew G. Knepley + name - name of the constructor
18894d4d2bdcSBarry Smith - function - constructor routine, see `PCMGCoarseSpaceConstructorFn`
1890f3b08a26SMatthew G. Knepley
1891f3b08a26SMatthew G. Knepley Level: advanced
1892f3b08a26SMatthew G. Knepley
1893feefa0e1SJacob Faibussowitsch Developer Notes:
18944d4d2bdcSBarry Smith This does not appear to be used anywhere
1895f1580f4eSBarry Smith
18964d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1897f3b08a26SMatthew G. Knepley @*/
PCMGRegisterCoarseSpaceConstructor(const char name[],PCMGCoarseSpaceConstructorFn * function)18984d4d2bdcSBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function)
1899d71ae5a4SJacob Faibussowitsch {
1900f3b08a26SMatthew G. Knepley PetscFunctionBegin;
19019566063dSJacob Faibussowitsch PetscCall(PCInitializePackage());
19029566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
19033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1904f3b08a26SMatthew G. Knepley }
1905f3b08a26SMatthew G. Knepley
1906f3b08a26SMatthew G. Knepley /*@C
1907f3b08a26SMatthew G. Knepley PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method.
1908f3b08a26SMatthew G. Knepley
1909cc4c1da9SBarry Smith Not Collective, No Fortran Support
1910f3b08a26SMatthew G. Knepley
1911f3b08a26SMatthew G. Knepley Input Parameter:
1912f3b08a26SMatthew G. Knepley . name - name of the constructor
1913f3b08a26SMatthew G. Knepley
1914f3b08a26SMatthew G. Knepley Output Parameter:
1915f3b08a26SMatthew G. Knepley . function - constructor routine
1916f3b08a26SMatthew G. Knepley
1917f3b08a26SMatthew G. Knepley Level: advanced
1918f3b08a26SMatthew G. Knepley
19194d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1920f3b08a26SMatthew G. Knepley @*/
PCMGGetCoarseSpaceConstructor(const char name[],PCMGCoarseSpaceConstructorFn ** function)19214d4d2bdcSBarry Smith PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function)
1922d71ae5a4SJacob Faibussowitsch {
1923f3b08a26SMatthew G. Knepley PetscFunctionBegin;
19249566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
19253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1926f3b08a26SMatthew G. Knepley }
1927f3b08a26SMatthew G. Knepley
19283b09bd56SBarry Smith /*MC
1929efba3485SBarry Smith PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional information about the restriction/interpolation
1930efba3485SBarry Smith operators using `PCMGSetInterpolation()` and/or `PCMGSetRestriction()`(and possibly the coarser grid matrices) or a `DM` that can provide such information.
19313b09bd56SBarry Smith
19323b09bd56SBarry Smith Options Database Keys:
19333b09bd56SBarry Smith + -pc_mg_levels <nlevels> - number of levels including finest
1934391689abSStefano Zampini . -pc_mg_cycle_type <v,w> - provide the cycle desired
19358c1c2452SJed Brown . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
19363b09bd56SBarry Smith . -pc_mg_log - log information about time spent on each level of the solver
1937710315b6SLawrence Mitchell . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
1938efba3485SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - use the Galerkin process to compute coarser operators, i.e., $A_{coarse} = R A_{fine} R^T$
19398cf6037eSBarry Smith . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
19408cf6037eSBarry Smith . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1941a3b724e8SBarry Smith to a `PETSCVIEWERSOCKET` for reading from MATLAB.
19428cf6037eSBarry Smith - -pc_mg_dump_binary -dumps the matrices for each level and the restriction/interpolation matrices
19438cf6037eSBarry Smith to the binary output file called binaryoutput
19443b09bd56SBarry Smith
194520f4b53cSBarry Smith Level: intermediate
194620f4b53cSBarry Smith
194795452b02SPatrick Sanan Notes:
1948efba3485SBarry Smith `PCMG` provides a general framework for implementing multigrid methods. Use `PCGAMG` for PETSc's algebraic multigrid preconditioner, `PCHYPRE` for hypre's
1949efba3485SBarry Smith BoomerAMG algebraic multigrid, and `PCML` for Trilinos's ML preconditioner. `PCAMGX` provides access to NVIDIA's AmgX algebraic multigrid.
1950efba3485SBarry Smith
1951efba3485SBarry Smith If you use `KSPSetDM()` (or `SNESSetDM()` or `TSSetDM()`) with an appropriate `DM`, such as `DMDA`, then `PCMG` will use the geometric information
1952efba3485SBarry Smith from the `DM` to generate appropriate restriction and interpolation information and construct a geometric multigrid.
1953efba3485SBarry Smith
1954efba3485SBarry Smith If you do not provide an appropriate `DM` and do not provide restriction or interpolation operators with `PCMGSetInterpolation()` and/or `PCMGSetRestriction()`,
1955efba3485SBarry Smith then `PCMG` will run multigrid with only a single level (so not really multigrid).
1956efba3485SBarry Smith
195704c3f3b8SBarry Smith The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard
19588f4fb22eSMark Adams options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`,
19598f4fb22eSMark Adams and the finest where `-mg_fine_` can override `-mg_levels_`. One can set different preconditioners etc on specific levels with the prefix
19608f4fb22eSMark Adams `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example
196104c3f3b8SBarry Smith .vb
196204c3f3b8SBarry Smith -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor
196304c3f3b8SBarry Smith .ve
196404c3f3b8SBarry Smith These options also work for controlling the smoothers etc inside `PCGAMG`
196504c3f3b8SBarry Smith
1966e87b5d96SPierre Jolivet If one uses a Krylov method such `KSPGMRES` or `KSPCG` as the smoother than one must use `KSPFGMRES`, `KSPGCR`, or `KSPRICHARDSON` as the outer Krylov method
19673b09bd56SBarry Smith
19688cf6037eSBarry Smith When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19698cf6037eSBarry Smith
1970f1580f4eSBarry Smith When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
197123067569SBarry Smith is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
197223067569SBarry Smith (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
197323067569SBarry Smith residual is computed at the end of each cycle.
197423067569SBarry Smith
197504c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1976db781477SPatrick Sanan `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1977db781477SPatrick Sanan `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1978db781477SPatrick Sanan `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1979f1580f4eSBarry Smith `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1980f1580f4eSBarry Smith `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19813b09bd56SBarry Smith M*/
19823b09bd56SBarry Smith
PCCreate_MG(PC pc)1983d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1984d71ae5a4SJacob Faibussowitsch {
1985f3fbd535SBarry Smith PC_MG *mg;
1986f3fbd535SBarry Smith
19874b9ad928SBarry Smith PetscFunctionBegin;
19884dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mg));
19893ec1f749SStefano Zampini pc->data = mg;
1990f3fbd535SBarry Smith mg->nlevels = -1;
199110eca3edSLisandro Dalcin mg->am = PC_MG_MULTIPLICATIVE;
19922134b1e4SBarry Smith mg->galerkin = PC_MG_GALERKIN_NONE;
1993f3b08a26SMatthew G. Knepley mg->adaptInterpolation = PETSC_FALSE;
1994f3b08a26SMatthew G. Knepley mg->Nc = -1;
1995f3b08a26SMatthew G. Knepley mg->eigenvalue = -1;
1996f3fbd535SBarry Smith
199737a44384SMark Adams pc->useAmat = PETSC_TRUE;
199837a44384SMark Adams
19994b9ad928SBarry Smith pc->ops->apply = PCApply_MG;
2000fcb023d4SJed Brown pc->ops->applytranspose = PCApplyTranspose_MG;
200130b0564aSStefano Zampini pc->ops->matapply = PCMatApply_MG;
20024dbf25a8SPierre Jolivet pc->ops->matapplytranspose = PCMatApplyTranspose_MG;
20034b9ad928SBarry Smith pc->ops->setup = PCSetUp_MG;
2004a06653b4SBarry Smith pc->ops->reset = PCReset_MG;
20054b9ad928SBarry Smith pc->ops->destroy = PCDestroy_MG;
20064b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_MG;
20074b9ad928SBarry Smith pc->ops->view = PCView_MG;
2008fb15c04eSBarry Smith
20099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
20109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
2011bbbcb081SMark Adams PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", PCSetReusePreconditioner_MG));
20129566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
20139566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
20149566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
20159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
20169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
20179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
20189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
20199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
20202b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
20212b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
20223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
20234b9ad928SBarry Smith }
2024