14b9ad928SBarry Smith /* 24b9ad928SBarry Smith Defines the multigrid preconditioner interface. 34b9ad928SBarry Smith */ 4af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 541b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h> 61e25c274SJed Brown #include <petscdm.h> 7391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *); 84b9ad928SBarry Smith 9f3b08a26SMatthew G. Knepley /* 10f3b08a26SMatthew G. Knepley Contains the list of registered coarse space construction routines 11f3b08a26SMatthew G. Knepley */ 12f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL; 13f3b08a26SMatthew G. Knepley 14d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) 15d71ae5a4SJacob Faibussowitsch { 1631567311SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1731567311SBarry Smith PC_MG_Levels *mgc, *mglevels = *mglevelsin; 18835f2295SStefano Zampini PetscInt cycles = (mglevels->level == 1) ? 1 : mglevels->cycles; 194b9ad928SBarry Smith 204b9ad928SBarry Smith PetscFunctionBegin; 219566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 22fcb023d4SJed Brown if (!transpose) { 2330b0564aSStefano Zampini if (matapp) { 249566063dSJacob Faibussowitsch PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */ 259566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL)); 2630b0564aSStefano Zampini } else { 279566063dSJacob Faibussowitsch PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */ 289566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 2930b0564aSStefano Zampini } 30fcb023d4SJed Brown } else { 3128b400f6SJacob Faibussowitsch PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 329566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */ 339566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 34fcb023d4SJed Brown } 359566063dSJacob Faibussowitsch if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 3631567311SBarry Smith if (mglevels->level) { /* not the coarsest grid */ 379566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0)); 3848a46eb9SPierre Jolivet if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R)); 39fcb023d4SJed Brown if (!transpose) { 409566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 419566063dSJacob Faibussowitsch else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 42fcb023d4SJed Brown } else { 439566063dSJacob Faibussowitsch if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 449566063dSJacob Faibussowitsch else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 45fcb023d4SJed Brown } 469566063dSJacob Faibussowitsch if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0)); 474b9ad928SBarry Smith 484b9ad928SBarry Smith /* if on finest level and have convergence criteria set */ 4931567311SBarry Smith if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) { 504b9ad928SBarry Smith PetscReal rnorm; 51*218e2965SBarry 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 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; 166*218e2965SBarry 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 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 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 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 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 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 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; 424*218e2965SBarry 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 46697d33e41SMatthew G. Knepley Level: intermediate 46797d33e41SMatthew G. Knepley 46897d33e41SMatthew G. Knepley Notes: 46920f4b53cSBarry Smith If the number of levels is one then the multigrid uses the `-mg_levels` prefix 4708f4fb22eSMark Adams for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix. 47197d33e41SMatthew G. Knepley 472d5a8f7e6SBarry Smith You can free the information in comms after this routine is called. 473d5a8f7e6SBarry Smith 474f1580f4eSBarry Smith The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level 475d5a8f7e6SBarry Smith are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on 476d5a8f7e6SBarry Smith the two levels, rank 0 in the original communicator will pass in an array of 2 communicators 477d5a8f7e6SBarry Smith of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators 478f1580f4eSBarry Smith the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate 479d5a8f7e6SBarry Smith in the coarse grid solve. 480d5a8f7e6SBarry Smith 481f1580f4eSBarry Smith Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one 482d5a8f7e6SBarry Smith must take special care in providing the restriction and interpolation operation. We recommend 483d5a8f7e6SBarry Smith providing these as two step operations; first perform a standard restriction or interpolation on 484d5a8f7e6SBarry Smith the full number of ranks for that level and then use an MPI call to copy the resulting vector 48505552d4bSJunchao Zhang array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both 486d5a8f7e6SBarry Smith cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and 48720f4b53cSBarry Smith receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries. 488d5a8f7e6SBarry Smith 489feefa0e1SJacob Faibussowitsch Fortran Notes: 49020f4b53cSBarry Smith Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM` 491f1580f4eSBarry Smith is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc. 492d5a8f7e6SBarry Smith 493562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()` 49497d33e41SMatthew G. Knepley @*/ 495d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) 496d71ae5a4SJacob Faibussowitsch { 49797d33e41SMatthew G. Knepley PetscFunctionBegin; 49897d33e41SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 4994f572ea9SToby Isaac if (comms) PetscAssertPointer(comms, 3); 500cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms)); 5013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 50297d33e41SMatthew G. Knepley } 50397d33e41SMatthew G. Knepley 504d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc) 505d71ae5a4SJacob Faibussowitsch { 506a06653b4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 507a06653b4SBarry Smith PC_MG_Levels **mglevels = mg->levels; 508a06653b4SBarry Smith PetscInt i, n; 509c07bf074SBarry Smith 510c07bf074SBarry Smith PetscFunctionBegin; 5119566063dSJacob Faibussowitsch PetscCall(PCReset_MG(pc)); 512a06653b4SBarry Smith if (mglevels) { 513a06653b4SBarry Smith n = mglevels[0]->levels; 514a06653b4SBarry Smith for (i = 0; i < n; i++) { 51548a46eb9SPierre Jolivet if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 5169566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 5179566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&mglevels[i]->cr)); 5189566063dSJacob Faibussowitsch PetscCall(PetscFree(mglevels[i])); 519a06653b4SBarry Smith } 5209566063dSJacob Faibussowitsch PetscCall(PetscFree(mg->levels)); 521a06653b4SBarry Smith } 5229566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 5239566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5249566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5252b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL)); 526bbbcb081SMark Adams PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", NULL)); 5272b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL)); 5282b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL)); 5292b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 5302b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 5312b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL)); 5322b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL)); 5332b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL)); 5342b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL)); 5352b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL)); 5362b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL)); 5373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 538f3fbd535SBarry Smith } 539f3fbd535SBarry Smith 540f3fbd535SBarry Smith /* 541f3fbd535SBarry Smith PCApply_MG - Runs either an additive, multiplicative, Kaskadic 542f3fbd535SBarry Smith or full cycle of multigrid. 543f3fbd535SBarry Smith 544f3fbd535SBarry Smith Note: 545f3fbd535SBarry Smith A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 546f3fbd535SBarry Smith */ 547d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) 548d71ae5a4SJacob Faibussowitsch { 549f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 550f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 551391689abSStefano Zampini PC tpc; 552f3fbd535SBarry Smith PetscInt levels = mglevels[0]->levels, i; 55330b0564aSStefano Zampini PetscBool changeu, changed, matapp; 554f3fbd535SBarry Smith 555f3fbd535SBarry Smith PetscFunctionBegin; 55630b0564aSStefano Zampini matapp = (PetscBool)(B && X); 5579566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply)); 558e1d8e5deSBarry Smith /* When the DM is supplying the matrix then it will not exist until here */ 559298cc208SBarry Smith for (i = 0; i < levels; i++) { 560e1d8e5deSBarry Smith if (!mglevels[i]->A) { 5619566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 5629566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 563e1d8e5deSBarry Smith } 564e1d8e5deSBarry Smith } 565e1d8e5deSBarry Smith 5669566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 5679566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 5689566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 5699566063dSJacob Faibussowitsch PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 570391689abSStefano Zampini if (!changeu && !changed) { 57130b0564aSStefano Zampini if (matapp) { 5729566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 57330b0564aSStefano Zampini mglevels[levels - 1]->B = B; 57430b0564aSStefano Zampini } else { 5759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 576f3fbd535SBarry Smith mglevels[levels - 1]->b = b; 57730b0564aSStefano Zampini } 578391689abSStefano Zampini } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 57930b0564aSStefano Zampini if (matapp) { 58030b0564aSStefano Zampini if (mglevels[levels - 1]->B) { 58130b0564aSStefano Zampini PetscInt N1, N2; 58230b0564aSStefano Zampini PetscBool flg; 58330b0564aSStefano Zampini 5849566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1)); 5859566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N2)); 5869566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg)); 58748a46eb9SPierre Jolivet if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 58830b0564aSStefano Zampini } 58930b0564aSStefano Zampini if (!mglevels[levels - 1]->B) { 5909566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B)); 59130b0564aSStefano Zampini } else { 5929566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN)); 59330b0564aSStefano Zampini } 59430b0564aSStefano Zampini } else { 595391689abSStefano Zampini if (!mglevels[levels - 1]->b) { 596391689abSStefano Zampini Vec *vec; 597391689abSStefano Zampini 5989566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 599391689abSStefano Zampini mglevels[levels - 1]->b = *vec; 6009566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 601391689abSStefano Zampini } 6029566063dSJacob Faibussowitsch PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 603391689abSStefano Zampini } 60430b0564aSStefano Zampini } 6059371c9d4SSatish Balay if (matapp) { 6069371c9d4SSatish Balay mglevels[levels - 1]->X = X; 6079371c9d4SSatish Balay } else { 6089371c9d4SSatish Balay mglevels[levels - 1]->x = x; 6099371c9d4SSatish Balay } 61030b0564aSStefano Zampini 61130b0564aSStefano Zampini /* If coarser Xs are present, it means we have already block applied the PC at least once 61230b0564aSStefano Zampini Reset operators if sizes/type do no match */ 61330b0564aSStefano Zampini if (matapp && levels > 1 && mglevels[levels - 2]->X) { 61430b0564aSStefano Zampini PetscInt Xc, Bc; 61530b0564aSStefano Zampini PetscBool flg; 61630b0564aSStefano Zampini 6179566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc)); 6189566063dSJacob Faibussowitsch PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc)); 6199566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg)); 62030b0564aSStefano Zampini if (Xc != Bc || !flg) { 6219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[levels - 1]->R)); 62230b0564aSStefano Zampini for (i = 0; i < levels - 1; i++) { 6239566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->R)); 6249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->B)); 6259566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mglevels[i]->X)); 62630b0564aSStefano Zampini } 62730b0564aSStefano Zampini } 62830b0564aSStefano Zampini } 629391689abSStefano Zampini 63031567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 6319566063dSJacob Faibussowitsch if (matapp) PetscCall(MatZeroEntries(X)); 6329566063dSJacob Faibussowitsch else PetscCall(VecZeroEntries(x)); 63348a46eb9SPierre Jolivet for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL)); 6342fa5cd67SKarl Rupp } else if (mg->am == PC_MG_ADDITIVE) { 6359566063dSJacob Faibussowitsch PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp)); 6362fa5cd67SKarl Rupp } else if (mg->am == PC_MG_KASKADE) { 6379566063dSJacob Faibussowitsch PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp)); 6382fa5cd67SKarl Rupp } else { 6399566063dSJacob Faibussowitsch PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp)); 640f3fbd535SBarry Smith } 6419566063dSJacob Faibussowitsch if (mg->stageApply) PetscCall(PetscLogStagePop()); 64230b0564aSStefano Zampini if (!changeu && !changed) { 6439371c9d4SSatish Balay if (matapp) { 6449371c9d4SSatish Balay mglevels[levels - 1]->B = NULL; 6459371c9d4SSatish Balay } else { 6469371c9d4SSatish Balay mglevels[levels - 1]->b = NULL; 6479371c9d4SSatish Balay } 64830b0564aSStefano Zampini } 6493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 650f3fbd535SBarry Smith } 651f3fbd535SBarry Smith 652d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) 653d71ae5a4SJacob Faibussowitsch { 654fcb023d4SJed Brown PetscFunctionBegin; 6559566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE)); 6563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 657fcb023d4SJed Brown } 658fcb023d4SJed Brown 659d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) 660d71ae5a4SJacob Faibussowitsch { 661fcb023d4SJed Brown PetscFunctionBegin; 6629566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE)); 6633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66430b0564aSStefano Zampini } 66530b0564aSStefano Zampini 666d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) 667d71ae5a4SJacob Faibussowitsch { 66830b0564aSStefano Zampini PetscFunctionBegin; 6699566063dSJacob Faibussowitsch PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE)); 6703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 671fcb023d4SJed Brown } 672f3fbd535SBarry Smith 6734dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x) 6744dbf25a8SPierre Jolivet { 6754dbf25a8SPierre Jolivet PetscFunctionBegin; 6764dbf25a8SPierre Jolivet PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE)); 6774dbf25a8SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 6784dbf25a8SPierre Jolivet } 6794dbf25a8SPierre Jolivet 680ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject) 681d71ae5a4SJacob Faibussowitsch { 682710315b6SLawrence Mitchell PetscInt levels, cycles; 683f3b08a26SMatthew G. Knepley PetscBool flg, flg2; 684f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 6853d3eaba7SBarry Smith PC_MG_Levels **mglevels; 686f3fbd535SBarry Smith PCMGType mgtype; 687f3fbd535SBarry Smith PCMGCycleType mgctype; 6882134b1e4SBarry Smith PCMGGalerkinType gtype; 6892b3cbbdaSStefano Zampini PCMGCoarseSpaceType coarseSpaceType; 690f3fbd535SBarry Smith 691f3fbd535SBarry Smith PetscFunctionBegin; 6921d743356SStefano Zampini levels = PetscMax(mg->nlevels, 1); 693d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options"); 6949566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg)); 6951a97d7b6SStefano Zampini if (!flg && !mg->levels && pc->dm) { 6969566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 697eb3f98d2SBarry Smith levels++; 6983aeaf226SBarry Smith mg->usedmfornumberoflevels = PETSC_TRUE; 699eb3f98d2SBarry Smith } 7009566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 7013aeaf226SBarry Smith mglevels = mg->levels; 7023aeaf226SBarry Smith 703f3fbd535SBarry Smith mgctype = (PCMGCycleType)mglevels[0]->cycles; 7049566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg)); 7051baa6e33SBarry Smith if (flg) PetscCall(PCMGSetCycleType(pc, mgctype)); 7062b3cbbdaSStefano Zampini coarseSpaceType = mg->coarseSpaceType; 7072b3cbbdaSStefano 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)); 7082b3cbbdaSStefano Zampini if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType)); 7099566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg)); 7109566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg)); 71141b6fd38SMatthew G. Knepley flg2 = PETSC_FALSE; 7129566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg)); 7139566063dSJacob Faibussowitsch if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2)); 714f56b1265SBarry Smith flg = PETSC_FALSE; 7159566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL)); 7161baa6e33SBarry Smith if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc)); 7175544a5bcSStefano Zampini PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)>ype, &flg)); 7185544a5bcSStefano Zampini if (flg) PetscCall(PCMGSetGalerkin(pc, gtype)); 71931567311SBarry Smith mgtype = mg->am; 7209566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg)); 7211baa6e33SBarry Smith if (flg) PetscCall(PCMGSetType(pc, mgtype)); 72231567311SBarry Smith if (mg->am == PC_MG_MULTIPLICATIVE) { 7239566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg)); 7241baa6e33SBarry Smith if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles)); 725f3fbd535SBarry Smith } 726f3fbd535SBarry Smith flg = PETSC_FALSE; 7279566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL)); 728f3fbd535SBarry Smith if (flg) { 729f3fbd535SBarry Smith PetscInt i; 730f3fbd535SBarry Smith char eventname[128]; 7311a97d7b6SStefano Zampini 732f3fbd535SBarry Smith levels = mglevels[0]->levels; 733f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 734835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i)); 7359566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup)); 736835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i)); 7379566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve)); 738f3fbd535SBarry Smith if (i) { 739835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i)); 7409566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual)); 741835f2295SStefano Zampini PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i)); 7429566063dSJacob Faibussowitsch PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict)); 743f3fbd535SBarry Smith } 744f3fbd535SBarry Smith } 745eec35531SMatthew G Knepley 7462611ad71SToby Isaac if (PetscDefined(USE_LOG)) { 7472611ad71SToby Isaac const char sname[] = "MG Apply"; 748eec35531SMatthew G Knepley 7492611ad71SToby Isaac PetscCall(PetscLogStageGetId(sname, &mg->stageApply)); 7502611ad71SToby Isaac if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply)); 751eec35531SMatthew G Knepley } 752f3fbd535SBarry Smith } 753d0609cedSBarry Smith PetscOptionsHeadEnd(); 754f3b08a26SMatthew G. Knepley /* Check option consistency */ 7559566063dSJacob Faibussowitsch PetscCall(PCMGGetGalerkin(pc, >ype)); 7569566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptInterpolation(pc, &flg)); 75708401ef6SPierre Jolivet PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator"); 7583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 759f3fbd535SBarry Smith } 760f3fbd535SBarry Smith 7610a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL}; 7620a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL}; 7630a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL}; 7642b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL}; 765f3fbd535SBarry Smith 7669804daf3SBarry Smith #include <petscdraw.h> 767d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) 768d71ae5a4SJacob Faibussowitsch { 769f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 770f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 771e3deeeafSJed Brown PetscInt levels = mglevels ? mglevels[0]->levels : 0, i; 7729f196a02SMartin Diehl PetscBool isascii, isbinary, isdraw; 773f3fbd535SBarry Smith 774f3fbd535SBarry Smith PetscFunctionBegin; 7759f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 7769566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 7779566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 7789f196a02SMartin Diehl if (isascii) { 779e3deeeafSJed Brown const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 78063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename)); 78148a46eb9SPierre Jolivet if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply)); 7822134b1e4SBarry Smith if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 7839566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n")); 7842134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 7859566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n")); 7862134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 7879566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n")); 7882134b1e4SBarry Smith } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 7899566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n")); 7904f66f45eSBarry Smith } else { 7919566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n")); 792f3fbd535SBarry Smith } 7931baa6e33SBarry Smith if (mg->view) PetscCall((*mg->view)(pc, viewer)); 794f3fbd535SBarry Smith for (i = 0; i < levels; i++) { 79563a3b9bcSJacob Faibussowitsch if (i) { 79663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 797f3fbd535SBarry Smith } else { 79863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 799f3fbd535SBarry Smith } 8009566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8019566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8029566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 803f3fbd535SBarry Smith if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 8049566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n")); 805f3fbd535SBarry Smith } else if (i) { 80663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 8079566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8089566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8099566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 810f3fbd535SBarry Smith } 81141b6fd38SMatthew G. Knepley if (i && mglevels[i]->cr) { 81263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i)); 8139566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8149566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->cr, viewer)); 8159566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 81641b6fd38SMatthew G. Knepley } 817f3fbd535SBarry Smith } 8185b0b0462SBarry Smith } else if (isbinary) { 8195b0b0462SBarry Smith for (i = levels - 1; i >= 0; i--) { 8209566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 82148a46eb9SPierre Jolivet if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8225b0b0462SBarry Smith } 823219b1045SBarry Smith } else if (isdraw) { 824219b1045SBarry Smith PetscDraw draw; 825b4375e8dSPeter Brune PetscReal x, w, y, bottom, th; 8269566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 8279566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 8289566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, NULL, &th)); 829219b1045SBarry Smith bottom = y - th; 830219b1045SBarry Smith for (i = levels - 1; i >= 0; i--) { 831b4375e8dSPeter Brune if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 8329566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 8339566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8349566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 835b4375e8dSPeter Brune } else { 836b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x); 8379566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 8389566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 8399566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 8409566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 8419566063dSJacob Faibussowitsch PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 8429566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 843b4375e8dSPeter Brune } 8449566063dSJacob Faibussowitsch PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL)); 8451cd381d6SBarry Smith bottom -= th; 846219b1045SBarry Smith } 8475b0b0462SBarry Smith } 8483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 849f3fbd535SBarry Smith } 850f3fbd535SBarry Smith 851af0996ceSBarry Smith #include <petsc/private/kspimpl.h> 852cab2e9ccSBarry Smith 853f3fbd535SBarry Smith /* 854f3fbd535SBarry Smith Calls setup for the KSP on each level 855f3fbd535SBarry Smith */ 856d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc) 857d71ae5a4SJacob Faibussowitsch { 858f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 859f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 8601a97d7b6SStefano Zampini PetscInt i, n; 86198e04984SBarry Smith PC cpc; 8623db492dfSBarry Smith PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE; 863f3fbd535SBarry Smith Mat dA, dB; 864f3fbd535SBarry Smith Vec tvec; 865218a07d4SBarry Smith DM *dms; 8660a545947SLisandro Dalcin PetscViewer viewer = NULL; 86741b6fd38SMatthew G. Knepley PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE; 8682b3cbbdaSStefano Zampini PetscBool adaptInterpolation = mg->adaptInterpolation; 869f3fbd535SBarry Smith 870f3fbd535SBarry Smith PetscFunctionBegin; 87128b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up"); 8721a97d7b6SStefano Zampini n = mglevels[0]->levels; 87301bc414fSDmitry Karpeev /* FIX: Move this to PCSetFromOptions_MG? */ 8743aeaf226SBarry Smith if (mg->usedmfornumberoflevels) { 8753aeaf226SBarry Smith PetscInt levels; 8769566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(pc->dm, &levels)); 8773aeaf226SBarry Smith levels++; 8783aeaf226SBarry Smith if (levels > n) { /* the problem is now being solved on a finer grid */ 8799566063dSJacob Faibussowitsch PetscCall(PCMGSetLevels(pc, levels, NULL)); 8803aeaf226SBarry Smith n = levels; 8819566063dSJacob Faibussowitsch PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 8823aeaf226SBarry Smith mglevels = mg->levels; 8833aeaf226SBarry Smith } 8843aeaf226SBarry Smith } 8853aeaf226SBarry Smith 886f3fbd535SBarry Smith /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 887f3fbd535SBarry Smith /* so use those from global PC */ 888f3fbd535SBarry Smith /* Is this what we always want? What if user wants to keep old one? */ 8899566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset)); 89098e04984SBarry Smith if (opsset) { 89198e04984SBarry Smith Mat mmat; 8929566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat)); 89398e04984SBarry Smith if (mmat == pc->pmat) opsset = PETSC_FALSE; 89498e04984SBarry Smith } 895bbbcb081SMark Adams /* fine grid smoother inherits the reuse-pc flag */ 896bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[n - 1]->smoothd, &cpc)); 897bbbcb081SMark Adams cpc->reusepreconditioner = pc->reusepreconditioner; 898bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[n - 1]->smoothu, &cpc)); 899bbbcb081SMark Adams cpc->reusepreconditioner = pc->reusepreconditioner; 9004a5f07a5SMark F. Adams 90141b6fd38SMatthew G. Knepley /* Create CR solvers */ 9029566063dSJacob Faibussowitsch PetscCall(PCMGGetAdaptCR(pc, &doCR)); 90341b6fd38SMatthew G. Knepley if (doCR) { 90441b6fd38SMatthew G. Knepley const char *prefix; 90541b6fd38SMatthew G. Knepley 9069566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 90741b6fd38SMatthew G. Knepley for (i = 1; i < n; ++i) { 90841b6fd38SMatthew G. Knepley PC ipc, cr; 90941b6fd38SMatthew G. Knepley char crprefix[128]; 91041b6fd38SMatthew G. Knepley 9119566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr)); 9123821be0aSBarry Smith PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel)); 9139566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 9149566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i)); 9159566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 9169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 9179566063dSJacob Faibussowitsch PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 9189566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 9199566063dSJacob Faibussowitsch PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 9209566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->cr, &ipc)); 92141b6fd38SMatthew G. Knepley 9229566063dSJacob Faibussowitsch PetscCall(PCSetType(ipc, PCCOMPOSITE)); 9239566063dSJacob Faibussowitsch PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 9249566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPCType(ipc, PCSOR)); 9259566063dSJacob Faibussowitsch PetscCall(CreateCR_Private(pc, i, &cr)); 9269566063dSJacob Faibussowitsch PetscCall(PCCompositeAddPC(ipc, cr)); 9279566063dSJacob Faibussowitsch PetscCall(PCDestroy(&cr)); 92841b6fd38SMatthew G. Knepley 929fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd)); 9309566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 931835f2295SStefano Zampini PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i)); 9329566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 93341b6fd38SMatthew G. Knepley } 93441b6fd38SMatthew G. Knepley } 93541b6fd38SMatthew G. Knepley 9364a5f07a5SMark F. Adams if (!opsset) { 9379566063dSJacob Faibussowitsch PetscCall(PCGetUseAmat(pc, &use_amat)); 9384a5f07a5SMark F. Adams if (use_amat) { 9399566063dSJacob 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")); 9409566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat)); 94169858f1bSStefano Zampini } else { 9429566063dSJacob 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")); 9439566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat)); 9444a5f07a5SMark F. Adams } 9454a5f07a5SMark F. Adams } 946f3fbd535SBarry Smith 9479c7ffb39SBarry Smith for (i = n - 1; i > 0; i--) { 9489c7ffb39SBarry Smith if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 9499c7ffb39SBarry Smith missinginterpolate = PETSC_TRUE; 9502b3cbbdaSStefano Zampini break; 9519c7ffb39SBarry Smith } 9529c7ffb39SBarry Smith } 9532134b1e4SBarry Smith 9549566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB)); 9552134b1e4SBarry Smith if (dA == dB) dAeqdB = PETSC_TRUE; 9563a7d0413SPierre 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 */ 9572134b1e4SBarry Smith 9582b3cbbdaSStefano Zampini if (pc->dm && !pc->setupcalled) { 9592b3cbbdaSStefano Zampini /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 9602b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm)); 9612b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE)); 9622b3cbbdaSStefano Zampini if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) { 9632b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm)); 9642b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE)); 9652b3cbbdaSStefano Zampini } 9662b3cbbdaSStefano Zampini if (mglevels[n - 1]->cr) { 9672b3cbbdaSStefano Zampini PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm)); 9682b3cbbdaSStefano Zampini PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE)); 9692b3cbbdaSStefano Zampini } 9702b3cbbdaSStefano Zampini } 9712b3cbbdaSStefano Zampini 9729c7ffb39SBarry Smith /* 9739c7ffb39SBarry Smith Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 9742b3cbbdaSStefano Zampini Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 9759c7ffb39SBarry Smith */ 97632fe681dSStefano Zampini if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 97732fe681dSStefano Zampini /* first see if we can compute a coarse space */ 97832fe681dSStefano Zampini if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) { 97932fe681dSStefano Zampini for (i = n - 2; i > -1; i--) { 98032fe681dSStefano Zampini if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) { 98132fe681dSStefano Zampini PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace)); 98232fe681dSStefano Zampini PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace)); 98332fe681dSStefano Zampini } 98432fe681dSStefano Zampini } 98532fe681dSStefano Zampini } else { /* construct the interpolation from the DMs */ 9862e499ae9SBarry Smith Mat p; 98773250ac0SBarry Smith Vec rscale; 9889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &dms)); 989218a07d4SBarry Smith dms[n - 1] = pc->dm; 990ef1267afSMatthew G. Knepley /* Separately create them so we do not get DMKSP interference between levels */ 9919566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i])); 992218a07d4SBarry Smith for (i = n - 2; i > -1; i--) { 993942e3340SBarry Smith DMKSP kdm; 994eab52d2bSLawrence Mitchell PetscBool dmhasrestrict, dmhasinject; 995*218e2965SBarry Smith 9969566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i])); 9979566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE)); 998c27ee7a3SPatrick Farrell if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 9999566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i])); 10009566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE)); 1001c27ee7a3SPatrick Farrell } 100241b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 10039566063dSJacob Faibussowitsch PetscCall(KSPSetDM(mglevels[i]->cr, dms[i])); 10049566063dSJacob Faibussowitsch if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE)); 100541b6fd38SMatthew G. Knepley } 10069566063dSJacob Faibussowitsch PetscCall(DMGetDMKSPWrite(dms[i], &kdm)); 1007d1a3e677SJed Brown /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 1008d1a3e677SJed Brown * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 10090298fd71SBarry Smith kdm->ops->computerhs = NULL; 10100298fd71SBarry Smith kdm->rhsctx = NULL; 101124c3aa18SBarry Smith if (!mglevels[i + 1]->interpolate) { 10129566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale)); 10139566063dSJacob Faibussowitsch PetscCall(PCMGSetInterpolation(pc, i + 1, p)); 10149566063dSJacob Faibussowitsch if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale)); 10159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rscale)); 10169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 1017218a07d4SBarry Smith } 10189566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict)); 10193ad4599aSBarry Smith if (dmhasrestrict && !mglevels[i + 1]->restrct) { 10209566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p)); 10219566063dSJacob Faibussowitsch PetscCall(PCMGSetRestriction(pc, i + 1, p)); 10229566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 10233ad4599aSBarry Smith } 10249566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(dms[i], &dmhasinject)); 1025eab52d2bSLawrence Mitchell if (dmhasinject && !mglevels[i + 1]->inject) { 10269566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p)); 10279566063dSJacob Faibussowitsch PetscCall(PCMGSetInjection(pc, i + 1, p)); 10289566063dSJacob Faibussowitsch PetscCall(MatDestroy(&p)); 1029eab52d2bSLawrence Mitchell } 103024c3aa18SBarry Smith } 10312d2b81a6SBarry Smith 10329566063dSJacob Faibussowitsch for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i])); 10339566063dSJacob Faibussowitsch PetscCall(PetscFree(dms)); 1034ce4cda84SJed Brown } 103532fe681dSStefano Zampini } 1036cab2e9ccSBarry Smith 10372134b1e4SBarry Smith if (mg->galerkin < PC_MG_GALERKIN_NONE) { 10382134b1e4SBarry Smith Mat A, B; 10392134b1e4SBarry Smith PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE; 10402134b1e4SBarry Smith MatReuse reuse = MAT_INITIAL_MATRIX; 10412134b1e4SBarry Smith 10422b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE; 10432b3cbbdaSStefano Zampini if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE; 10442134b1e4SBarry Smith if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 1045f3fbd535SBarry Smith for (i = n - 2; i > -1; i--) { 10467827d75bSBarry 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"); 104748a46eb9SPierre Jolivet if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct)); 104848a46eb9SPierre Jolivet if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate)); 104948a46eb9SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B)); 105048a46eb9SPierre Jolivet if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A)); 105148a46eb9SPierre Jolivet if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B)); 10522134b1e4SBarry Smith /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 10532134b1e4SBarry Smith if (!doA && dAeqdB) { 10549566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B)); 10552134b1e4SBarry Smith A = B; 10562134b1e4SBarry Smith } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 10579566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL)); 10589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 1059b9367914SBarry Smith } 10602134b1e4SBarry Smith if (!doB && dAeqdB) { 10619566063dSJacob Faibussowitsch if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A)); 10622134b1e4SBarry Smith B = A; 10632134b1e4SBarry Smith } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 10649566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B)); 10659566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 10667d537d92SJed Brown } 10672134b1e4SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 10689566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B)); 10699566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)A)); 10709566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)B)); 10712134b1e4SBarry Smith } 10722134b1e4SBarry Smith dA = A; 1073f3fbd535SBarry Smith dB = B; 1074f3fbd535SBarry Smith } 1075f3fbd535SBarry Smith } 1076f3b08a26SMatthew G. Knepley 1077f3b08a26SMatthew G. Knepley /* Adapt interpolation matrices */ 10782b3cbbdaSStefano Zampini if (adaptInterpolation) { 1079f3b08a26SMatthew G. Knepley for (i = 0; i < n; ++i) { 108048a46eb9SPierre Jolivet if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace)); 10812b3cbbdaSStefano Zampini if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace)); 1082f3b08a26SMatthew G. Knepley } 108348a46eb9SPierre Jolivet for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i)); 1084f3b08a26SMatthew G. Knepley } 1085f3b08a26SMatthew G. Knepley 10862134b1e4SBarry Smith if (needRestricts && pc->dm) { 1087caa4e7f2SJed Brown for (i = n - 2; i >= 0; i--) { 1088ccceb50cSJed Brown DM dmfine, dmcoarse; 1089caa4e7f2SJed Brown Mat Restrict, Inject; 1090caa4e7f2SJed Brown Vec rscale; 1091*218e2965SBarry Smith 10929566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine)); 10939566063dSJacob Faibussowitsch PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse)); 10949566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict)); 10959566063dSJacob Faibussowitsch PetscCall(PCMGGetRScale(pc, i + 1, &rscale)); 10969566063dSJacob Faibussowitsch PetscCall(PCMGGetInjection(pc, i + 1, &Inject)); 10979566063dSJacob Faibussowitsch PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse)); 1098caa4e7f2SJed Brown } 1099caa4e7f2SJed Brown } 1100f3fbd535SBarry Smith 1101f3fbd535SBarry Smith if (!pc->setupcalled) { 110248a46eb9SPierre Jolivet for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd)); 1103f3fbd535SBarry Smith for (i = 1; i < n; i++) { 110448a46eb9SPierre Jolivet if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu)); 110548a46eb9SPierre Jolivet if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr)); 1106f3fbd535SBarry Smith } 110715229ffcSPierre Jolivet /* insure that if either interpolation or restriction is set the other one is set */ 1108f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11099566063dSJacob Faibussowitsch PetscCall(PCMGGetInterpolation(pc, i, NULL)); 11109566063dSJacob Faibussowitsch PetscCall(PCMGGetRestriction(pc, i, NULL)); 1111f3fbd535SBarry Smith } 1112f3fbd535SBarry Smith for (i = 0; i < n - 1; i++) { 1113f3fbd535SBarry Smith if (!mglevels[i]->b) { 1114f3fbd535SBarry Smith Vec *vec; 11159566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL)); 11169566063dSJacob Faibussowitsch PetscCall(PCMGSetRhs(pc, i, *vec)); 11179566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11189566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1119f3fbd535SBarry Smith } 1120f3fbd535SBarry Smith if (!mglevels[i]->r && i) { 11219566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 11229566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, i, tvec)); 11239566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1124f3fbd535SBarry Smith } 1125f3fbd535SBarry Smith if (!mglevels[i]->x) { 11269566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 11279566063dSJacob Faibussowitsch PetscCall(PCMGSetX(pc, i, tvec)); 11289566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 1129f3fbd535SBarry Smith } 113041b6fd38SMatthew G. Knepley if (doCR) { 11319566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx)); 11329566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb)); 11339566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[i]->crb)); 113441b6fd38SMatthew G. Knepley } 1135f3fbd535SBarry Smith } 1136f3fbd535SBarry Smith if (n != 1 && !mglevels[n - 1]->r) { 1137f3fbd535SBarry Smith /* PCMGSetR() on the finest level if user did not supply it */ 1138f3fbd535SBarry Smith Vec *vec; 1139*218e2965SBarry Smith 11409566063dSJacob Faibussowitsch PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL)); 11419566063dSJacob Faibussowitsch PetscCall(PCMGSetR(pc, n - 1, *vec)); 11429566063dSJacob Faibussowitsch PetscCall(VecDestroy(vec)); 11439566063dSJacob Faibussowitsch PetscCall(PetscFree(vec)); 1144f3fbd535SBarry Smith } 114541b6fd38SMatthew G. Knepley if (doCR) { 11469566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx)); 11479566063dSJacob Faibussowitsch PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb)); 11489566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(mglevels[n - 1]->crb)); 114941b6fd38SMatthew G. Knepley } 1150f3fbd535SBarry Smith } 1151f3fbd535SBarry Smith 115298e04984SBarry Smith if (pc->dm) { 115398e04984SBarry Smith /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 115498e04984SBarry Smith for (i = 0; i < n - 1; i++) { 115598e04984SBarry Smith if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 115698e04984SBarry Smith } 115798e04984SBarry Smith } 115808549ed4SJed Brown // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g., 115908549ed4SJed Brown // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply. 116008549ed4SJed Brown if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1161f3fbd535SBarry Smith 1162f3fbd535SBarry Smith for (i = 1; i < n; i++) { 11632a21e185SBarry Smith if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1164f3fbd535SBarry Smith /* if doing only down then initial guess is zero */ 11659566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1166f3fbd535SBarry Smith } 11679566063dSJacob Faibussowitsch if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 11689566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11699566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothd)); 1170d4645a75SStefano Zampini if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 11719566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1172d42688cbSBarry Smith if (!mglevels[i]->residual) { 1173d42688cbSBarry Smith Mat mat; 1174*218e2965SBarry Smith 11759566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11769566063dSJacob Faibussowitsch PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat)); 1177d42688cbSBarry Smith } 1178fcb023d4SJed Brown if (!mglevels[i]->residualtranspose) { 1179fcb023d4SJed Brown Mat mat; 1180*218e2965SBarry Smith 11819566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 11829566063dSJacob Faibussowitsch PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat)); 1183fcb023d4SJed Brown } 1184f3fbd535SBarry Smith } 1185f3fbd535SBarry Smith for (i = 1; i < n; i++) { 1186f3fbd535SBarry Smith if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1187f3fbd535SBarry Smith Mat downmat, downpmat; 1188f3fbd535SBarry Smith 1189f3fbd535SBarry Smith /* check if operators have been set for up, if not use down operators to set them */ 11909566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL)); 1191f3fbd535SBarry Smith if (!opsset) { 11929566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 11939566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat)); 1194f3fbd535SBarry Smith } 1195f3fbd535SBarry Smith 11969566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE)); 11979566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 11989566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->smoothu)); 1199d4645a75SStefano Zampini if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR; 12009566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1201f3fbd535SBarry Smith } 120241b6fd38SMatthew G. Knepley if (mglevels[i]->cr) { 120341b6fd38SMatthew G. Knepley Mat downmat, downpmat; 120441b6fd38SMatthew G. Knepley 120541b6fd38SMatthew G. Knepley /* check if operators have been set for up, if not use down operators to set them */ 12069566063dSJacob Faibussowitsch PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL)); 120741b6fd38SMatthew G. Knepley if (!opsset) { 12089566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 12099566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat)); 121041b6fd38SMatthew G. Knepley } 121141b6fd38SMatthew G. Knepley 12129566063dSJacob Faibussowitsch PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 12139566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 12149566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[i]->cr)); 1215d4645a75SStefano Zampini if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR; 12169566063dSJacob Faibussowitsch if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 121741b6fd38SMatthew G. Knepley } 1218f3fbd535SBarry Smith } 1219f3fbd535SBarry Smith 12209566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 12219566063dSJacob Faibussowitsch PetscCall(KSPSetUp(mglevels[0]->smoothd)); 1222d4645a75SStefano Zampini if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 12239566063dSJacob Faibussowitsch if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1224f3fbd535SBarry Smith 1225f3fbd535SBarry Smith /* 1226f3fbd535SBarry Smith Dump the interpolation/restriction matrices plus the 1227e3c5b3baSBarry Smith Jacobian/stiffness on each level. This allows MATLAB users to 1228f3fbd535SBarry Smith easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1229f3fbd535SBarry Smith 1230f3fbd535SBarry Smith Only support one or the other at the same time. 1231f3fbd535SBarry Smith */ 1232f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER) 12339566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL)); 1234ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1235f3fbd535SBarry Smith dump = PETSC_FALSE; 1236f3fbd535SBarry Smith #endif 12379566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL)); 1238ce94432eSBarry Smith if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1239f3fbd535SBarry Smith 1240f3fbd535SBarry Smith if (viewer) { 124148a46eb9SPierre Jolivet for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer)); 1242f3fbd535SBarry Smith for (i = 0; i < n; i++) { 12439566063dSJacob Faibussowitsch PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc)); 12449566063dSJacob Faibussowitsch PetscCall(MatView(pc->mat, viewer)); 1245f3fbd535SBarry Smith } 1246f3fbd535SBarry Smith } 12473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1248f3fbd535SBarry Smith } 1249f3fbd535SBarry Smith 1250d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 1251d71ae5a4SJacob Faibussowitsch { 125297d33e41SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 125397d33e41SMatthew G. Knepley 125497d33e41SMatthew G. Knepley PetscFunctionBegin; 125597d33e41SMatthew G. Knepley *levels = mg->nlevels; 12563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 125797d33e41SMatthew G. Knepley } 125897d33e41SMatthew G. Knepley 12594b9ad928SBarry Smith /*@ 1260f1580f4eSBarry Smith PCMGGetLevels - Gets the number of levels to use with `PCMG`. 12614b9ad928SBarry Smith 12624b9ad928SBarry Smith Not Collective 12634b9ad928SBarry Smith 12644b9ad928SBarry Smith Input Parameter: 12654b9ad928SBarry Smith . pc - the preconditioner context 12664b9ad928SBarry Smith 1267feefa0e1SJacob Faibussowitsch Output Parameter: 12684b9ad928SBarry Smith . levels - the number of levels 12694b9ad928SBarry Smith 12704b9ad928SBarry Smith Level: advanced 12714b9ad928SBarry Smith 1272562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()` 12734b9ad928SBarry Smith @*/ 1274d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) 1275d71ae5a4SJacob Faibussowitsch { 12764b9ad928SBarry Smith PetscFunctionBegin; 12770700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 12784f572ea9SToby Isaac PetscAssertPointer(levels, 2); 127997d33e41SMatthew G. Knepley *levels = 0; 1280cac4c232SBarry Smith PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels)); 12813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12824b9ad928SBarry Smith } 12834b9ad928SBarry Smith 12844b9ad928SBarry Smith /*@ 1285f1580f4eSBarry Smith PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy 1286e7d4b4cbSMark Adams 1287e7d4b4cbSMark Adams Input Parameter: 1288e7d4b4cbSMark Adams . pc - the preconditioner context 1289e7d4b4cbSMark Adams 129090db8557SMark Adams Output Parameters: 129190db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0 129290db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0 1293e7d4b4cbSMark Adams 1294e7d4b4cbSMark Adams Level: advanced 1295e7d4b4cbSMark Adams 1296f1580f4eSBarry Smith Note: 1297f1580f4eSBarry Smith This is often call the operator complexity in multigrid literature 1298f1580f4eSBarry Smith 1299562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()` 1300e7d4b4cbSMark Adams @*/ 1301d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) 1302d71ae5a4SJacob Faibussowitsch { 1303e7d4b4cbSMark Adams PC_MG *mg = (PC_MG *)pc->data; 1304e7d4b4cbSMark Adams PC_MG_Levels **mglevels = mg->levels; 1305e7d4b4cbSMark Adams PetscInt lev, N; 1306e7d4b4cbSMark Adams PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1307e7d4b4cbSMark Adams MatInfo info; 1308e7d4b4cbSMark Adams 1309e7d4b4cbSMark Adams PetscFunctionBegin; 131090db8557SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 13114f572ea9SToby Isaac if (gc) PetscAssertPointer(gc, 2); 13124f572ea9SToby Isaac if (oc) PetscAssertPointer(oc, 3); 1313e7d4b4cbSMark Adams if (!pc->setupcalled) { 131490db8557SMark Adams if (gc) *gc = 0; 131590db8557SMark Adams if (oc) *oc = 0; 13163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1317e7d4b4cbSMark Adams } 1318e7d4b4cbSMark Adams PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels"); 1319e7d4b4cbSMark Adams for (lev = 0; lev < mg->nlevels; lev++) { 1320e7d4b4cbSMark Adams Mat dB; 13219566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB)); 13229566063dSJacob Faibussowitsch PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */ 13239566063dSJacob Faibussowitsch PetscCall(MatGetSize(dB, &N, NULL)); 1324e7d4b4cbSMark Adams sgc += N; 1325e7d4b4cbSMark Adams soc += info.nz_used; 13269371c9d4SSatish Balay if (lev == mg->nlevels - 1) { 13279371c9d4SSatish Balay nnz0 = info.nz_used; 13289371c9d4SSatish Balay n0 = N; 13299371c9d4SSatish Balay } 1330e7d4b4cbSMark Adams } 13310fdf79fbSJacob Faibussowitsch PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available"); 13320fdf79fbSJacob Faibussowitsch *gc = (PetscReal)(sgc / n0); 133390db8557SMark Adams if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0); 13343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1335e7d4b4cbSMark Adams } 1336e7d4b4cbSMark Adams 1337e7d4b4cbSMark Adams /*@ 133804c3f3b8SBarry Smith PCMGSetType - Determines the form of multigrid to use, either 13394b9ad928SBarry Smith multiplicative, additive, full, or the Kaskade algorithm. 13404b9ad928SBarry Smith 1341c3339decSBarry Smith Logically Collective 13424b9ad928SBarry Smith 13434b9ad928SBarry Smith Input Parameters: 13444b9ad928SBarry Smith + pc - the preconditioner context 1345f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE` 13464b9ad928SBarry Smith 13474b9ad928SBarry Smith Options Database Key: 134820f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade 13494b9ad928SBarry Smith 13504b9ad928SBarry Smith Level: advanced 13514b9ad928SBarry Smith 1352562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType` 13534b9ad928SBarry Smith @*/ 1354d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form) 1355d71ae5a4SJacob Faibussowitsch { 1356f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 13574b9ad928SBarry Smith 13584b9ad928SBarry Smith PetscFunctionBegin; 13590700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1360c5eb9154SBarry Smith PetscValidLogicalCollectiveEnum(pc, form, 2); 136131567311SBarry Smith mg->am = form; 13629dcbbd2bSBarry Smith if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1363c60c7ad4SBarry Smith else pc->ops->applyrichardson = NULL; 13643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1365c60c7ad4SBarry Smith } 1366c60c7ad4SBarry Smith 1367c60c7ad4SBarry Smith /*@ 1368f1580f4eSBarry Smith PCMGGetType - Finds the form of multigrid the `PCMG` is using multiplicative, additive, full, or the Kaskade algorithm. 1369c60c7ad4SBarry Smith 1370c3339decSBarry Smith Logically Collective 1371c60c7ad4SBarry Smith 1372c60c7ad4SBarry Smith Input Parameter: 1373c60c7ad4SBarry Smith . pc - the preconditioner context 1374c60c7ad4SBarry Smith 1375c60c7ad4SBarry Smith Output Parameter: 1376f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType` 1377c60c7ad4SBarry Smith 1378c60c7ad4SBarry Smith Level: advanced 1379c60c7ad4SBarry Smith 1380562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()` 1381c60c7ad4SBarry Smith @*/ 1382d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type) 1383d71ae5a4SJacob Faibussowitsch { 1384c60c7ad4SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1385c60c7ad4SBarry Smith 1386c60c7ad4SBarry Smith PetscFunctionBegin; 1387c60c7ad4SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1388c60c7ad4SBarry Smith *type = mg->am; 13893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13904b9ad928SBarry Smith } 13914b9ad928SBarry Smith 13924b9ad928SBarry Smith /*@ 1393f1580f4eSBarry Smith PCMGSetCycleType - Sets the type cycles to use. Use `PCMGSetCycleTypeOnLevel()` for more 13944b9ad928SBarry Smith complicated cycling. 13954b9ad928SBarry Smith 1396c3339decSBarry Smith Logically Collective 13974b9ad928SBarry Smith 13984b9ad928SBarry Smith Input Parameters: 1399c2be2410SBarry Smith + pc - the multigrid context 1400f1580f4eSBarry Smith - n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 14014b9ad928SBarry Smith 14024b9ad928SBarry Smith Options Database Key: 1403c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired 14044b9ad928SBarry Smith 14054b9ad928SBarry Smith Level: advanced 14064b9ad928SBarry Smith 1407562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType` 14084b9ad928SBarry Smith @*/ 1409d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) 1410d71ae5a4SJacob Faibussowitsch { 1411f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1412f3fbd535SBarry Smith PC_MG_Levels **mglevels = mg->levels; 141379416396SBarry Smith PetscInt i, levels; 14144b9ad928SBarry Smith 14154b9ad928SBarry Smith PetscFunctionBegin; 14160700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 141769fbec6eSBarry Smith PetscValidLogicalCollectiveEnum(pc, n, 2); 141828b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1419f3fbd535SBarry Smith levels = mglevels[0]->levels; 14202fa5cd67SKarl Rupp for (i = 0; i < levels; i++) mglevels[i]->cycles = n; 14213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14224b9ad928SBarry Smith } 14234b9ad928SBarry Smith 14248cc2d5dfSBarry Smith /*@ 14258cc2d5dfSBarry Smith PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1426f1580f4eSBarry Smith of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE` 14278cc2d5dfSBarry Smith 1428c3339decSBarry Smith Logically Collective 14298cc2d5dfSBarry Smith 14308cc2d5dfSBarry Smith Input Parameters: 14318cc2d5dfSBarry Smith + pc - the multigrid context 14328cc2d5dfSBarry Smith - n - number of cycles (default is 1) 14338cc2d5dfSBarry Smith 14348cc2d5dfSBarry Smith Options Database Key: 1435147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles 14368cc2d5dfSBarry Smith 14378cc2d5dfSBarry Smith Level: advanced 14388cc2d5dfSBarry Smith 1439f1580f4eSBarry Smith Note: 1440f1580f4eSBarry Smith This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()` 14418cc2d5dfSBarry Smith 1442562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType` 14438cc2d5dfSBarry Smith @*/ 1444d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) 1445d71ae5a4SJacob Faibussowitsch { 1446f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 14478cc2d5dfSBarry Smith 14488cc2d5dfSBarry Smith PetscFunctionBegin; 14490700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1450c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 14512a21e185SBarry Smith mg->cyclesperpcapply = n; 14523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14538cc2d5dfSBarry Smith } 14548cc2d5dfSBarry Smith 1455bbbcb081SMark Adams /* 1456bbbcb081SMark Adams Since the finest level KSP shares the original matrix (of the entire system), it's preconditioner 1457bbbcb081SMark Adams should not be updated if the whole PC is supposed to reuse the preconditioner 1458bbbcb081SMark Adams */ 1459bbbcb081SMark Adams static PetscErrorCode PCSetReusePreconditioner_MG(PC pc, PetscBool flag) 1460bbbcb081SMark Adams { 1461bbbcb081SMark Adams PC_MG *mg = (PC_MG *)pc->data; 1462bbbcb081SMark Adams PC_MG_Levels **mglevels = mg->levels; 1463bbbcb081SMark Adams PetscInt levels; 1464bbbcb081SMark Adams PC tpc; 1465bbbcb081SMark Adams 1466bbbcb081SMark Adams PetscFunctionBegin; 1467bbbcb081SMark Adams PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1468bbbcb081SMark Adams PetscValidLogicalCollectiveBool(pc, flag, 2); 1469bbbcb081SMark Adams if (mglevels) { 1470bbbcb081SMark Adams levels = mglevels[0]->levels; 1471bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 1472bbbcb081SMark Adams tpc->reusepreconditioner = flag; 1473bbbcb081SMark Adams PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 1474bbbcb081SMark Adams tpc->reusepreconditioner = flag; 1475bbbcb081SMark Adams } 1476bbbcb081SMark Adams PetscFunctionReturn(PETSC_SUCCESS); 1477bbbcb081SMark Adams } 1478bbbcb081SMark Adams 147966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) 1480d71ae5a4SJacob Faibussowitsch { 1481fb15c04eSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1482fb15c04eSBarry Smith 1483fb15c04eSBarry Smith PetscFunctionBegin; 14842134b1e4SBarry Smith mg->galerkin = use; 14853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1486fb15c04eSBarry Smith } 1487fb15c04eSBarry Smith 1488c2be2410SBarry Smith /*@ 148997177400SBarry Smith PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 149082b87d87SMatthew G. Knepley finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1491c2be2410SBarry Smith 1492c3339decSBarry Smith Logically Collective 1493c2be2410SBarry Smith 1494c2be2410SBarry Smith Input Parameters: 1495c91913d3SJed Brown + pc - the multigrid context 1496f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE` 1497c2be2410SBarry Smith 1498c2be2410SBarry Smith Options Database Key: 1499147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1500c2be2410SBarry Smith 1501c2be2410SBarry Smith Level: intermediate 1502c2be2410SBarry Smith 1503f1580f4eSBarry Smith Note: 1504f1580f4eSBarry Smith Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not 1505f1580f4eSBarry Smith use the `PCMG` construction of the coarser grids. 15061c1aac46SBarry Smith 1507562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType` 1508c2be2410SBarry Smith @*/ 1509d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) 1510d71ae5a4SJacob Faibussowitsch { 1511c2be2410SBarry Smith PetscFunctionBegin; 15120700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1513cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use)); 15143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1515c2be2410SBarry Smith } 1516c2be2410SBarry Smith 15173fc8bf9cSBarry Smith /*@ 1518f1580f4eSBarry Smith PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i 15193fc8bf9cSBarry Smith 15203fc8bf9cSBarry Smith Not Collective 15213fc8bf9cSBarry Smith 15223fc8bf9cSBarry Smith Input Parameter: 15233fc8bf9cSBarry Smith . pc - the multigrid context 15243fc8bf9cSBarry Smith 15253fc8bf9cSBarry Smith Output Parameter: 1526f1580f4eSBarry 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` 15273fc8bf9cSBarry Smith 15283fc8bf9cSBarry Smith Level: intermediate 15293fc8bf9cSBarry Smith 1530562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType` 15313fc8bf9cSBarry Smith @*/ 1532d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) 1533d71ae5a4SJacob Faibussowitsch { 1534f3fbd535SBarry Smith PC_MG *mg = (PC_MG *)pc->data; 15353fc8bf9cSBarry Smith 15363fc8bf9cSBarry Smith PetscFunctionBegin; 15370700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 15382134b1e4SBarry Smith *galerkin = mg->galerkin; 15393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15403fc8bf9cSBarry Smith } 15413fc8bf9cSBarry Smith 154266976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) 1543d71ae5a4SJacob Faibussowitsch { 1544f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1545f3b08a26SMatthew G. Knepley 1546f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1547f3b08a26SMatthew G. Knepley mg->adaptInterpolation = adapt; 15483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1549f3b08a26SMatthew G. Knepley } 1550f3b08a26SMatthew G. Knepley 155166976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) 1552d71ae5a4SJacob Faibussowitsch { 1553f3b08a26SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 1554f3b08a26SMatthew G. Knepley 1555f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1556f3b08a26SMatthew G. Knepley *adapt = mg->adaptInterpolation; 15573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1558f3b08a26SMatthew G. Knepley } 1559f3b08a26SMatthew G. Knepley 156066976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) 1561d71ae5a4SJacob Faibussowitsch { 15622b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15632b3cbbdaSStefano Zampini 15642b3cbbdaSStefano Zampini PetscFunctionBegin; 15652b3cbbdaSStefano Zampini mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE; 15662b3cbbdaSStefano Zampini mg->coarseSpaceType = ctype; 1567a077d33dSBarry Smith PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH)); 15683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15692b3cbbdaSStefano Zampini } 15702b3cbbdaSStefano Zampini 157166976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) 1572d71ae5a4SJacob Faibussowitsch { 15732b3cbbdaSStefano Zampini PC_MG *mg = (PC_MG *)pc->data; 15742b3cbbdaSStefano Zampini 15752b3cbbdaSStefano Zampini PetscFunctionBegin; 15762b3cbbdaSStefano Zampini *ctype = mg->coarseSpaceType; 15773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15782b3cbbdaSStefano Zampini } 15792b3cbbdaSStefano Zampini 158066976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) 1581d71ae5a4SJacob Faibussowitsch { 158241b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 158341b6fd38SMatthew G. Knepley 158441b6fd38SMatthew G. Knepley PetscFunctionBegin; 158541b6fd38SMatthew G. Knepley mg->compatibleRelaxation = cr; 15863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 158741b6fd38SMatthew G. Knepley } 158841b6fd38SMatthew G. Knepley 158966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) 1590d71ae5a4SJacob Faibussowitsch { 159141b6fd38SMatthew G. Knepley PC_MG *mg = (PC_MG *)pc->data; 159241b6fd38SMatthew G. Knepley 159341b6fd38SMatthew G. Knepley PetscFunctionBegin; 159441b6fd38SMatthew G. Knepley *cr = mg->compatibleRelaxation; 15953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 159641b6fd38SMatthew G. Knepley } 159741b6fd38SMatthew G. Knepley 1598cc4c1da9SBarry Smith /*@ 15992b3cbbdaSStefano Zampini PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space. 16002b3cbbdaSStefano Zampini 16012b3cbbdaSStefano 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. 16022b3cbbdaSStefano Zampini 1603c3339decSBarry Smith Logically Collective 16042b3cbbdaSStefano Zampini 16052b3cbbdaSStefano Zampini Input Parameters: 16062b3cbbdaSStefano Zampini + pc - the multigrid context 16072b3cbbdaSStefano Zampini - ctype - the type of coarse space 16082b3cbbdaSStefano Zampini 16092b3cbbdaSStefano Zampini Options Database Keys: 16102b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int> - The number of modes to use 1611a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw` 16122b3cbbdaSStefano Zampini 16132b3cbbdaSStefano Zampini Level: intermediate 16142b3cbbdaSStefano Zampini 1615a077d33dSBarry Smith Note: 1616a077d33dSBarry Smith Requires a `DM` with specific functionality be attached to the `PC`. 1617a077d33dSBarry Smith 1618a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM` 16192b3cbbdaSStefano Zampini @*/ 1620d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) 1621d71ae5a4SJacob Faibussowitsch { 16222b3cbbdaSStefano Zampini PetscFunctionBegin; 16232b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16242b3cbbdaSStefano Zampini PetscValidLogicalCollectiveEnum(pc, ctype, 2); 16252b3cbbdaSStefano Zampini PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype)); 16263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16272b3cbbdaSStefano Zampini } 16282b3cbbdaSStefano Zampini 1629cc4c1da9SBarry Smith /*@ 16302b3cbbdaSStefano Zampini PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space. 16312b3cbbdaSStefano Zampini 16322b3cbbdaSStefano Zampini Not Collective 16332b3cbbdaSStefano Zampini 16342b3cbbdaSStefano Zampini Input Parameter: 16352b3cbbdaSStefano Zampini . pc - the multigrid context 16362b3cbbdaSStefano Zampini 16372b3cbbdaSStefano Zampini Output Parameter: 16382b3cbbdaSStefano Zampini . ctype - the type of coarse space 16392b3cbbdaSStefano Zampini 16402b3cbbdaSStefano Zampini Level: intermediate 16412b3cbbdaSStefano Zampini 1642562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()` 16432b3cbbdaSStefano Zampini @*/ 1644d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) 1645d71ae5a4SJacob Faibussowitsch { 16462b3cbbdaSStefano Zampini PetscFunctionBegin; 16472b3cbbdaSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 16484f572ea9SToby Isaac PetscAssertPointer(ctype, 2); 16492b3cbbdaSStefano Zampini PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype)); 16503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16512b3cbbdaSStefano Zampini } 16522b3cbbdaSStefano Zampini 16532b3cbbdaSStefano Zampini /* MATT: REMOVE? */ 1654f3b08a26SMatthew G. Knepley /*@ 1655f3b08a26SMatthew 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. 1656f3b08a26SMatthew G. Knepley 1657c3339decSBarry Smith Logically Collective 1658f3b08a26SMatthew G. Knepley 1659f3b08a26SMatthew G. Knepley Input Parameters: 1660f3b08a26SMatthew G. Knepley + pc - the multigrid context 1661f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator 1662f3b08a26SMatthew G. Knepley 1663f3b08a26SMatthew G. Knepley Options Database Keys: 1664f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp - Turn on adaptation 1665f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1666f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1667f3b08a26SMatthew G. Knepley 1668f3b08a26SMatthew G. Knepley Level: intermediate 1669f3b08a26SMatthew G. Knepley 1670562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1671f3b08a26SMatthew G. Knepley @*/ 1672d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) 1673d71ae5a4SJacob Faibussowitsch { 1674f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1675f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1676cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt)); 16773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1678f3b08a26SMatthew G. Knepley } 1679f3b08a26SMatthew G. Knepley 1680f3b08a26SMatthew G. Knepley /*@ 1681f1580f4eSBarry Smith PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, 1682f1580f4eSBarry Smith and thus accurately interpolated. 1683f3b08a26SMatthew G. Knepley 168420f4b53cSBarry Smith Not Collective 1685f3b08a26SMatthew G. Knepley 1686f3b08a26SMatthew G. Knepley Input Parameter: 1687f3b08a26SMatthew G. Knepley . pc - the multigrid context 1688f3b08a26SMatthew G. Knepley 1689f3b08a26SMatthew G. Knepley Output Parameter: 1690f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator 1691f3b08a26SMatthew G. Knepley 1692f3b08a26SMatthew G. Knepley Level: intermediate 1693f3b08a26SMatthew G. Knepley 1694562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1695f3b08a26SMatthew G. Knepley @*/ 1696d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) 1697d71ae5a4SJacob Faibussowitsch { 1698f3b08a26SMatthew G. Knepley PetscFunctionBegin; 1699f3b08a26SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 17004f572ea9SToby Isaac PetscAssertPointer(adapt, 2); 1701cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt)); 17023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1703f3b08a26SMatthew G. Knepley } 1704f3b08a26SMatthew G. Knepley 17054b9ad928SBarry Smith /*@ 170641b6fd38SMatthew G. Knepley PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 170741b6fd38SMatthew G. Knepley 1708c3339decSBarry Smith Logically Collective 170941b6fd38SMatthew G. Knepley 171041b6fd38SMatthew G. Knepley Input Parameters: 171141b6fd38SMatthew G. Knepley + pc - the multigrid context 171241b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation 171341b6fd38SMatthew G. Knepley 1714f1580f4eSBarry Smith Options Database Key: 171541b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation 171641b6fd38SMatthew G. Knepley 171741b6fd38SMatthew G. Knepley Level: intermediate 171841b6fd38SMatthew G. Knepley 1719562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 172041b6fd38SMatthew G. Knepley @*/ 1721d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) 1722d71ae5a4SJacob Faibussowitsch { 172341b6fd38SMatthew G. Knepley PetscFunctionBegin; 172441b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1725cac4c232SBarry Smith PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr)); 17263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 172741b6fd38SMatthew G. Knepley } 172841b6fd38SMatthew G. Knepley 172941b6fd38SMatthew G. Knepley /*@ 173041b6fd38SMatthew G. Knepley PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 173141b6fd38SMatthew G. Knepley 173220f4b53cSBarry Smith Not Collective 173341b6fd38SMatthew G. Knepley 173441b6fd38SMatthew G. Knepley Input Parameter: 173541b6fd38SMatthew G. Knepley . pc - the multigrid context 173641b6fd38SMatthew G. Knepley 173741b6fd38SMatthew G. Knepley Output Parameter: 173841b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion 173941b6fd38SMatthew G. Knepley 174041b6fd38SMatthew G. Knepley Level: intermediate 174141b6fd38SMatthew G. Knepley 1742562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 174341b6fd38SMatthew G. Knepley @*/ 1744d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) 1745d71ae5a4SJacob Faibussowitsch { 174641b6fd38SMatthew G. Knepley PetscFunctionBegin; 174741b6fd38SMatthew G. Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 17484f572ea9SToby Isaac PetscAssertPointer(cr, 2); 1749cac4c232SBarry Smith PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr)); 17503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 175141b6fd38SMatthew G. Knepley } 175241b6fd38SMatthew G. Knepley 175341b6fd38SMatthew G. Knepley /*@ 175406792cafSBarry Smith PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1755f1580f4eSBarry Smith on all levels. Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of 1756710315b6SLawrence Mitchell pre- and post-smoothing steps. 175706792cafSBarry Smith 1758c3339decSBarry Smith Logically Collective 175906792cafSBarry Smith 176006792cafSBarry Smith Input Parameters: 1761feefa0e1SJacob Faibussowitsch + pc - the multigrid context 176206792cafSBarry Smith - n - the number of smoothing steps 176306792cafSBarry Smith 176406792cafSBarry Smith Options Database Key: 1765a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 176606792cafSBarry Smith 176706792cafSBarry Smith Level: advanced 176806792cafSBarry Smith 1769f1580f4eSBarry Smith Note: 1770f1580f4eSBarry 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. 177106792cafSBarry Smith 1772562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()` 177306792cafSBarry Smith @*/ 1774d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) 1775d71ae5a4SJacob Faibussowitsch { 177606792cafSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 177706792cafSBarry Smith PC_MG_Levels **mglevels = mg->levels; 177806792cafSBarry Smith PetscInt i, levels; 177906792cafSBarry Smith 178006792cafSBarry Smith PetscFunctionBegin; 178106792cafSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 178206792cafSBarry Smith PetscValidLogicalCollectiveInt(pc, n, 2); 178328b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 178406792cafSBarry Smith levels = mglevels[0]->levels; 178506792cafSBarry Smith 178606792cafSBarry Smith for (i = 1; i < levels; i++) { 1787fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 1788fb842aefSJose E. Roman PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 178906792cafSBarry Smith mg->default_smoothu = n; 179006792cafSBarry Smith mg->default_smoothd = n; 179106792cafSBarry Smith } 17923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 179306792cafSBarry Smith } 179406792cafSBarry Smith 1795f442ab6aSBarry Smith /*@ 1796f1580f4eSBarry Smith PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels 1797710315b6SLawrence Mitchell and adds the suffix _up to the options name 1798f442ab6aSBarry Smith 1799c3339decSBarry Smith Logically Collective 1800f442ab6aSBarry Smith 1801f1580f4eSBarry Smith Input Parameter: 1802f442ab6aSBarry Smith . pc - the preconditioner context 1803f442ab6aSBarry Smith 1804f442ab6aSBarry Smith Options Database Key: 1805147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1806f442ab6aSBarry Smith 1807f442ab6aSBarry Smith Level: advanced 1808f442ab6aSBarry Smith 1809f1580f4eSBarry Smith Note: 1810f1580f4eSBarry 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. 1811f442ab6aSBarry Smith 1812562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()` 1813f442ab6aSBarry Smith @*/ 1814d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1815d71ae5a4SJacob Faibussowitsch { 1816f442ab6aSBarry Smith PC_MG *mg = (PC_MG *)pc->data; 1817f442ab6aSBarry Smith PC_MG_Levels **mglevels = mg->levels; 1818f442ab6aSBarry Smith PetscInt i, levels; 1819f442ab6aSBarry Smith KSP subksp; 1820f442ab6aSBarry Smith 1821f442ab6aSBarry Smith PetscFunctionBegin; 1822f442ab6aSBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 182328b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1824f442ab6aSBarry Smith levels = mglevels[0]->levels; 1825f442ab6aSBarry Smith 1826f442ab6aSBarry Smith for (i = 1; i < levels; i++) { 1827710315b6SLawrence Mitchell const char *prefix = NULL; 1828f442ab6aSBarry Smith /* make sure smoother up and down are different */ 18299566063dSJacob Faibussowitsch PetscCall(PCMGGetSmootherUp(pc, i, &subksp)); 18309566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix)); 18319566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(subksp, prefix)); 18329566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(subksp, "up_")); 1833f442ab6aSBarry Smith } 18343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1835f442ab6aSBarry Smith } 1836f442ab6aSBarry Smith 183707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 183866976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) 1839d71ae5a4SJacob Faibussowitsch { 184007a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 184107a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 184207a4832bSFande Kong Mat *mat; 184307a4832bSFande Kong PetscInt l; 184407a4832bSFande Kong 184507a4832bSFande Kong PetscFunctionBegin; 184628b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 18479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 184807a4832bSFande Kong for (l = 1; l < mg->nlevels; l++) { 184907a4832bSFande Kong mat[l - 1] = mglevels[l]->interpolate; 18509566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l - 1])); 185107a4832bSFande Kong } 185207a4832bSFande Kong *num_levels = mg->nlevels; 185307a4832bSFande Kong *interpolations = mat; 18543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 185507a4832bSFande Kong } 185607a4832bSFande Kong 185707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 185866976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) 1859d71ae5a4SJacob Faibussowitsch { 186007a4832bSFande Kong PC_MG *mg = (PC_MG *)pc->data; 186107a4832bSFande Kong PC_MG_Levels **mglevels = mg->levels; 186207a4832bSFande Kong PetscInt l; 186307a4832bSFande Kong Mat *mat; 186407a4832bSFande Kong 186507a4832bSFande Kong PetscFunctionBegin; 186628b400f6SJacob Faibussowitsch PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 18679566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(mg->nlevels, &mat)); 186807a4832bSFande Kong for (l = 0; l < mg->nlevels - 1; l++) { 1869f4f49eeaSPierre Jolivet PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l])); 18709566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat[l])); 187107a4832bSFande Kong } 187207a4832bSFande Kong *num_levels = mg->nlevels; 187307a4832bSFande Kong *coarseOperators = mat; 18743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 187507a4832bSFande Kong } 187607a4832bSFande Kong 1877f3b08a26SMatthew G. Knepley /*@C 1878f1580f4eSBarry Smith PCMGRegisterCoarseSpaceConstructor - Adds a method to the `PCMG` package for coarse space construction. 1879f3b08a26SMatthew G. Knepley 1880cc4c1da9SBarry Smith Not Collective, No Fortran Support 1881f3b08a26SMatthew G. Knepley 1882f3b08a26SMatthew G. Knepley Input Parameters: 1883f3b08a26SMatthew G. Knepley + name - name of the constructor 18844d4d2bdcSBarry Smith - function - constructor routine, see `PCMGCoarseSpaceConstructorFn` 1885f3b08a26SMatthew G. Knepley 1886f3b08a26SMatthew G. Knepley Level: advanced 1887f3b08a26SMatthew G. Knepley 1888feefa0e1SJacob Faibussowitsch Developer Notes: 18894d4d2bdcSBarry Smith This does not appear to be used anywhere 1890f1580f4eSBarry Smith 18914d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()` 1892f3b08a26SMatthew G. Knepley @*/ 18934d4d2bdcSBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function) 1894d71ae5a4SJacob Faibussowitsch { 1895f3b08a26SMatthew G. Knepley PetscFunctionBegin; 18969566063dSJacob Faibussowitsch PetscCall(PCInitializePackage()); 18979566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function)); 18983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1899f3b08a26SMatthew G. Knepley } 1900f3b08a26SMatthew G. Knepley 1901f3b08a26SMatthew G. Knepley /*@C 1902f3b08a26SMatthew G. Knepley PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1903f3b08a26SMatthew G. Knepley 1904cc4c1da9SBarry Smith Not Collective, No Fortran Support 1905f3b08a26SMatthew G. Knepley 1906f3b08a26SMatthew G. Knepley Input Parameter: 1907f3b08a26SMatthew G. Knepley . name - name of the constructor 1908f3b08a26SMatthew G. Knepley 1909f3b08a26SMatthew G. Knepley Output Parameter: 1910f3b08a26SMatthew G. Knepley . function - constructor routine 1911f3b08a26SMatthew G. Knepley 1912f3b08a26SMatthew G. Knepley Level: advanced 1913f3b08a26SMatthew G. Knepley 19144d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()` 1915f3b08a26SMatthew G. Knepley @*/ 19164d4d2bdcSBarry Smith PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function) 1917d71ae5a4SJacob Faibussowitsch { 1918f3b08a26SMatthew G. Knepley PetscFunctionBegin; 19199566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function)); 19203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1921f3b08a26SMatthew G. Knepley } 1922f3b08a26SMatthew G. Knepley 19233b09bd56SBarry Smith /*MC 1924ccb205f8SBarry Smith PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 19253b09bd56SBarry Smith information about the coarser grid matrices and restriction/interpolation operators. 19263b09bd56SBarry Smith 19273b09bd56SBarry Smith Options Database Keys: 19283b09bd56SBarry Smith + -pc_mg_levels <nlevels> - number of levels including finest 1929391689abSStefano Zampini . -pc_mg_cycle_type <v,w> - provide the cycle desired 19308c1c2452SJed Brown . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 19313b09bd56SBarry Smith . -pc_mg_log - log information about time spent on each level of the solver 1932710315b6SLawrence Mitchell . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 19332134b1e4SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 19348cf6037eSBarry Smith . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 19358cf6037eSBarry Smith . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1936a3b724e8SBarry Smith to a `PETSCVIEWERSOCKET` for reading from MATLAB. 19378cf6037eSBarry Smith - -pc_mg_dump_binary -dumps the matrices for each level and the restriction/interpolation matrices 19388cf6037eSBarry Smith to the binary output file called binaryoutput 19393b09bd56SBarry Smith 194020f4b53cSBarry Smith Level: intermediate 194120f4b53cSBarry Smith 194295452b02SPatrick Sanan Notes: 194304c3f3b8SBarry Smith The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard 19448f4fb22eSMark Adams options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`, 19458f4fb22eSMark Adams and the finest where `-mg_fine_` can override `-mg_levels_`. One can set different preconditioners etc on specific levels with the prefix 19468f4fb22eSMark Adams `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example 194704c3f3b8SBarry Smith .vb 194804c3f3b8SBarry Smith -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor 194904c3f3b8SBarry Smith .ve 195004c3f3b8SBarry Smith These options also work for controlling the smoothers etc inside `PCGAMG` 195104c3f3b8SBarry Smith 1952e87b5d96SPierre 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 19533b09bd56SBarry Smith 19548cf6037eSBarry Smith When run with a single level the smoother options are used on that level NOT the coarse grid solver options 19558cf6037eSBarry Smith 1956f1580f4eSBarry Smith When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 195723067569SBarry Smith is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 195823067569SBarry Smith (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 195923067569SBarry Smith residual is computed at the end of each cycle. 196023067569SBarry Smith 196104c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE` 1962db781477SPatrick Sanan `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`, 1963db781477SPatrick Sanan `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`, 1964db781477SPatrick Sanan `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, 1965f1580f4eSBarry Smith `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`, 1966f1580f4eSBarry Smith `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 19673b09bd56SBarry Smith M*/ 19683b09bd56SBarry Smith 1969d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1970d71ae5a4SJacob Faibussowitsch { 1971f3fbd535SBarry Smith PC_MG *mg; 1972f3fbd535SBarry Smith 19734b9ad928SBarry Smith PetscFunctionBegin; 19744dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&mg)); 19753ec1f749SStefano Zampini pc->data = mg; 1976f3fbd535SBarry Smith mg->nlevels = -1; 197710eca3edSLisandro Dalcin mg->am = PC_MG_MULTIPLICATIVE; 19782134b1e4SBarry Smith mg->galerkin = PC_MG_GALERKIN_NONE; 1979f3b08a26SMatthew G. Knepley mg->adaptInterpolation = PETSC_FALSE; 1980f3b08a26SMatthew G. Knepley mg->Nc = -1; 1981f3b08a26SMatthew G. Knepley mg->eigenvalue = -1; 1982f3fbd535SBarry Smith 198337a44384SMark Adams pc->useAmat = PETSC_TRUE; 198437a44384SMark Adams 19854b9ad928SBarry Smith pc->ops->apply = PCApply_MG; 1986fcb023d4SJed Brown pc->ops->applytranspose = PCApplyTranspose_MG; 198730b0564aSStefano Zampini pc->ops->matapply = PCMatApply_MG; 19884dbf25a8SPierre Jolivet pc->ops->matapplytranspose = PCMatApplyTranspose_MG; 19894b9ad928SBarry Smith pc->ops->setup = PCSetUp_MG; 1990a06653b4SBarry Smith pc->ops->reset = PCReset_MG; 19914b9ad928SBarry Smith pc->ops->destroy = PCDestroy_MG; 19924b9ad928SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_MG; 19934b9ad928SBarry Smith pc->ops->view = PCView_MG; 1994fb15c04eSBarry Smith 19959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue)); 19969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG)); 1997bbbcb081SMark Adams PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", PCSetReusePreconditioner_MG)); 19989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG)); 19999566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG)); 20009566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG)); 20019566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG)); 20029566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG)); 20039566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG)); 20049566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG)); 20059566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG)); 20062b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG)); 20072b3cbbdaSStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG)); 20083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20094b9ad928SBarry Smith } 2010