1 /* 2 Defines the multigrid preconditioner interface. 3 */ 4 #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 5 #include <petsc/private/kspimpl.h> 6 #include <petscdm.h> 7 PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *); 8 9 /* 10 Contains the list of registered coarse space construction routines 11 */ 12 PetscFunctionList PCMGCoarseList = NULL; 13 14 PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) 15 { 16 PC_MG *mg = (PC_MG *)pc->data; 17 PC_MG_Levels *mgc, *mglevels = *mglevelsin; 18 PetscInt cycles = (mglevels->level == 1) ? 1 : mglevels->cycles; 19 20 PetscFunctionBegin; 21 if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 22 if (!transpose) { 23 if (matapp) { 24 PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */ 25 PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL)); 26 } else { 27 PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */ 28 PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 29 } 30 } else { 31 PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 32 PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */ 33 PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 34 } 35 if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 36 if (mglevels->level) { /* not the coarsest grid */ 37 if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0)); 38 if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R)); 39 if (!transpose) { 40 if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 41 else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 42 } else { 43 if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R)); 44 else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r)); 45 } 46 if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0)); 47 48 /* if on finest level and have convergence criteria set */ 49 if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) { 50 PetscReal rnorm; 51 PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm)); 52 if (rnorm <= mg->ttol) { 53 if (rnorm < mg->abstol) { 54 *reason = PCRICHARDSON_CONVERGED_ATOL; 55 PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol)); 56 } else { 57 *reason = PCRICHARDSON_CONVERGED_RTOL; 58 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)); 59 } 60 PetscFunctionReturn(PETSC_SUCCESS); 61 } 62 } 63 64 mgc = *(mglevelsin - 1); 65 if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 66 if (!transpose) { 67 if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B)); 68 else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b)); 69 } else { 70 if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B)); 71 else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b)); 72 } 73 if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 74 if (matapp) { 75 if (!mgc->X) { 76 PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X)); 77 } else { 78 PetscCall(MatZeroEntries(mgc->X)); 79 } 80 } else { 81 PetscCall(VecZeroEntries(mgc->x)); 82 } 83 while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason)); 84 if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0)); 85 if (!transpose) { 86 if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X)); 87 else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x)); 88 } else { 89 PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x)); 90 } 91 if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0)); 92 if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 93 if (!transpose) { 94 if (matapp) { 95 PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */ 96 PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL)); 97 } else { 98 PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */ 99 PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x)); 100 } 101 } else { 102 PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 103 PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */ 104 PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x)); 105 } 106 if (mglevels->cr) { 107 Mat crA; 108 109 PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported"); 110 /* TODO Turn on copy and turn off noisy if we have an exact solution 111 PetscCall(VecCopy(mglevels->x, mglevels->crx)); 112 PetscCall(VecCopy(mglevels->b, mglevels->crb)); */ 113 PetscCall(KSPGetOperators(mglevels->cr, &crA, NULL)); 114 PetscCall(KSPSetNoisy_Private(crA, mglevels->crx)); 115 PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */ 116 PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx)); 117 } 118 if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0)); 119 } 120 PetscFunctionReturn(PETSC_SUCCESS); 121 } 122 123 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) 124 { 125 PC_MG *mg = (PC_MG *)pc->data; 126 PC_MG_Levels **mglevels = mg->levels; 127 PC tpc; 128 PetscBool changeu, changed; 129 PetscInt levels = mglevels[0]->levels, i; 130 131 PetscFunctionBegin; 132 /* When the DM is supplying the matrix then it will not exist until here */ 133 for (i = 0; i < levels; i++) { 134 if (!mglevels[i]->A) { 135 PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 136 PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 137 } 138 } 139 140 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 141 PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 142 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 143 PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 144 if (!changed && !changeu) { 145 PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 146 mglevels[levels - 1]->b = b; 147 } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 148 if (!mglevels[levels - 1]->b) { 149 Vec *vec; 150 151 PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 152 mglevels[levels - 1]->b = *vec; 153 PetscCall(PetscFree(vec)); 154 } 155 PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 156 } 157 mglevels[levels - 1]->x = x; 158 159 mg->rtol = rtol; 160 mg->abstol = abstol; 161 mg->dtol = dtol; 162 if (rtol) { 163 /* compute initial residual norm for relative convergence test */ 164 PetscReal rnorm; 165 if (zeroguess) { 166 PetscCall(VecNorm(b, NORM_2, &rnorm)); 167 } else { 168 PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w)); 169 PetscCall(VecNorm(w, NORM_2, &rnorm)); 170 } 171 mg->ttol = PetscMax(rtol * rnorm, abstol); 172 } else if (abstol) mg->ttol = abstol; 173 else mg->ttol = 0.0; 174 175 /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 176 stop prematurely due to small residual */ 177 for (i = 1; i < levels; i++) { 178 PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT)); 179 if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 180 /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */ 181 PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 182 PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT)); 183 } 184 } 185 186 *reason = PCRICHARDSON_NOT_SET; 187 for (i = 0; i < its; i++) { 188 PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason)); 189 if (*reason) break; 190 } 191 if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS; 192 *outits = i; 193 if (!changed && !changeu) mglevels[levels - 1]->b = NULL; 194 PetscFunctionReturn(PETSC_SUCCESS); 195 } 196 197 PetscErrorCode PCReset_MG(PC pc) 198 { 199 PC_MG *mg = (PC_MG *)pc->data; 200 PC_MG_Levels **mglevels = mg->levels; 201 PetscInt i, n; 202 203 PetscFunctionBegin; 204 if (mglevels) { 205 n = mglevels[0]->levels; 206 for (i = 0; i < n - 1; i++) { 207 PetscCall(VecDestroy(&mglevels[i + 1]->r)); 208 PetscCall(VecDestroy(&mglevels[i]->b)); 209 PetscCall(VecDestroy(&mglevels[i]->x)); 210 PetscCall(MatDestroy(&mglevels[i + 1]->R)); 211 PetscCall(MatDestroy(&mglevels[i]->B)); 212 PetscCall(MatDestroy(&mglevels[i]->X)); 213 PetscCall(VecDestroy(&mglevels[i]->crx)); 214 PetscCall(VecDestroy(&mglevels[i]->crb)); 215 PetscCall(MatDestroy(&mglevels[i + 1]->restrct)); 216 PetscCall(MatDestroy(&mglevels[i + 1]->interpolate)); 217 PetscCall(MatDestroy(&mglevels[i + 1]->inject)); 218 PetscCall(VecDestroy(&mglevels[i + 1]->rscale)); 219 } 220 PetscCall(VecDestroy(&mglevels[n - 1]->crx)); 221 PetscCall(VecDestroy(&mglevels[n - 1]->crb)); 222 /* this is not null only if the smoother on the finest level 223 changes the rhs during PreSolve */ 224 PetscCall(VecDestroy(&mglevels[n - 1]->b)); 225 PetscCall(MatDestroy(&mglevels[n - 1]->B)); 226 227 for (i = 0; i < n; i++) { 228 PetscCall(MatDestroy(&mglevels[i]->coarseSpace)); 229 PetscCall(MatDestroy(&mglevels[i]->A)); 230 if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd)); 231 PetscCall(KSPReset(mglevels[i]->smoothu)); 232 if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr)); 233 } 234 mg->Nc = 0; 235 } 236 PetscFunctionReturn(PETSC_SUCCESS); 237 } 238 239 /* Implementing CR 240 241 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 242 243 Inj^T (Inj Inj^T)^{-1} Inj 244 245 and if Inj is a VecScatter, as it is now in PETSc, we have 246 247 Inj^T Inj 248 249 and 250 251 S = I - Inj^T Inj 252 253 since 254 255 Inj S = Inj - (Inj Inj^T) Inj = 0. 256 257 Brannick suggests 258 259 A \to S^T A S \qquad\mathrm{and}\qquad M \to S^T M S 260 261 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 262 263 M^{-1} A \to S M^{-1} A S 264 265 In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left. 266 267 Check: || Inj P - I ||_F < tol 268 Check: In general, Inj Inj^T = I 269 */ 270 271 typedef struct { 272 PC mg; /* The PCMG object */ 273 PetscInt l; /* The multigrid level for this solver */ 274 Mat Inj; /* The injection matrix */ 275 Mat S; /* I - Inj^T Inj */ 276 } CRContext; 277 278 static PetscErrorCode CRSetup_Private(PC pc) 279 { 280 CRContext *ctx; 281 Mat It; 282 283 PetscFunctionBeginUser; 284 PetscCall(PCShellGetContext(pc, &ctx)); 285 PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It)); 286 PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG"); 287 PetscCall(MatCreateTranspose(It, &ctx->Inj)); 288 PetscCall(MatCreateNormal(ctx->Inj, &ctx->S)); 289 PetscCall(MatScale(ctx->S, -1.0)); 290 PetscCall(MatShift(ctx->S, 1.0)); 291 PetscFunctionReturn(PETSC_SUCCESS); 292 } 293 294 static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y) 295 { 296 CRContext *ctx; 297 298 PetscFunctionBeginUser; 299 PetscCall(PCShellGetContext(pc, &ctx)); 300 PetscCall(MatMult(ctx->S, x, y)); 301 PetscFunctionReturn(PETSC_SUCCESS); 302 } 303 304 static PetscErrorCode CRDestroy_Private(PC pc) 305 { 306 CRContext *ctx; 307 308 PetscFunctionBeginUser; 309 PetscCall(PCShellGetContext(pc, &ctx)); 310 PetscCall(MatDestroy(&ctx->Inj)); 311 PetscCall(MatDestroy(&ctx->S)); 312 PetscCall(PetscFree(ctx)); 313 PetscCall(PCShellSetContext(pc, NULL)); 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr) 318 { 319 CRContext *ctx; 320 321 PetscFunctionBeginUser; 322 PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr)); 323 PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)")); 324 PetscCall(PetscCalloc1(1, &ctx)); 325 ctx->mg = pc; 326 ctx->l = l; 327 PetscCall(PCSetType(*cr, PCSHELL)); 328 PetscCall(PCShellSetContext(*cr, ctx)); 329 PetscCall(PCShellSetApply(*cr, CRApply_Private)); 330 PetscCall(PCShellSetSetUp(*cr, CRSetup_Private)); 331 PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private)); 332 PetscFunctionReturn(PETSC_SUCCESS); 333 } 334 335 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *); 336 337 PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms) 338 { 339 PC_MG *mg = (PC_MG *)pc->data; 340 MPI_Comm comm; 341 PC_MG_Levels **mglevels = mg->levels; 342 PCMGType mgtype = mg->am; 343 PetscInt mgctype = (PetscInt)PC_MG_CYCLE_V; 344 PetscInt i; 345 PetscMPIInt size; 346 const char *prefix; 347 PC ipc; 348 PetscInt n; 349 350 PetscFunctionBegin; 351 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 352 PetscValidLogicalCollectiveInt(pc, levels, 2); 353 if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS); 354 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 355 if (mglevels) { 356 mgctype = mglevels[0]->cycles; 357 /* changing the number of levels so free up the previous stuff */ 358 PetscCall(PCReset_MG(pc)); 359 n = mglevels[0]->levels; 360 for (i = 0; i < n; i++) { 361 if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 362 PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 363 PetscCall(KSPDestroy(&mglevels[i]->cr)); 364 PetscCall(PetscFree(mglevels[i])); 365 } 366 PetscCall(PetscFree(mg->levels)); 367 } 368 369 mg->nlevels = levels; 370 371 PetscCall(PetscMalloc1(levels, &mglevels)); 372 373 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 374 375 mg->stageApply = 0; 376 for (i = 0; i < levels; i++) { 377 PetscCall(PetscNew(&mglevels[i])); 378 379 mglevels[i]->level = i; 380 mglevels[i]->levels = levels; 381 mglevels[i]->cycles = mgctype; 382 mg->default_smoothu = 2; 383 mg->default_smoothd = 2; 384 mglevels[i]->eventsmoothsetup = 0; 385 mglevels[i]->eventsmoothsolve = 0; 386 mglevels[i]->eventresidual = 0; 387 mglevels[i]->eventinterprestrict = 0; 388 389 if (comms) comm = comms[i]; 390 if (comm != MPI_COMM_NULL) { 391 PetscCall(KSPCreate(comm, &mglevels[i]->smoothd)); 392 PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel)); 393 PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure)); 394 PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i)); 395 PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix)); 396 PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level)); 397 if (i == 0 && levels > 1) { // coarse grid 398 PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_")); 399 400 /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 401 PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY)); 402 PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc)); 403 PetscCallMPI(MPI_Comm_size(comm, &size)); 404 if (size > 1) { 405 PetscCall(PCSetType(ipc, PCREDUNDANT)); 406 } else { 407 PetscCall(PCSetType(ipc, PCLU)); 408 } 409 PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS)); 410 } else { 411 char tprefix[128]; 412 413 PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV)); 414 PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL)); 415 PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE)); 416 PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc)); 417 PetscCall(PCSetType(ipc, PCSOR)); 418 PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd)); 419 420 if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_' 421 PetscBool set; 422 PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set)); 423 if (set) { 424 if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix)); 425 else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_")); 426 PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix)); 427 } else { 428 PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i)); 429 PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 430 } 431 } else { 432 PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i)); 433 PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix)); 434 } 435 } 436 } 437 mglevels[i]->smoothu = mglevels[i]->smoothd; 438 mg->rtol = 0.0; 439 mg->abstol = 0.0; 440 mg->dtol = 0.0; 441 mg->ttol = 0.0; 442 mg->cyclesperpcapply = 1; 443 } 444 mg->levels = mglevels; 445 PetscCall(PCMGSetType(pc, mgtype)); 446 PetscFunctionReturn(PETSC_SUCCESS); 447 } 448 449 /*@C 450 PCMGSetLevels - Sets the number of levels to use with `PCMG`. 451 Must be called before any other `PCMG` routine. 452 453 Logically Collective 454 455 Input Parameters: 456 + pc - the preconditioner context 457 . levels - the number of levels 458 - comms - optional communicators for each level; this is to allow solving the coarser problems 459 on smaller sets of processes. For processes that are not included in the computation 460 you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes 461 should participate in each level of problem. 462 463 Level: intermediate 464 465 Notes: 466 If the number of levels is one then the multigrid uses the `-mg_levels` prefix 467 for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix. 468 469 You can free the information in comms after this routine is called. 470 471 The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level 472 are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on 473 the two levels, rank 0 in the original communicator will pass in an array of 2 communicators 474 of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators 475 the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate 476 in the coarse grid solve. 477 478 Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one 479 must take special care in providing the restriction and interpolation operation. We recommend 480 providing these as two step operations; first perform a standard restriction or interpolation on 481 the full number of ranks for that level and then use an MPI call to copy the resulting vector 482 array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both 483 cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and 484 receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries. 485 486 Fortran Notes: 487 Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM` 488 is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc. 489 490 .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()` 491 @*/ 492 PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) 493 { 494 PetscFunctionBegin; 495 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 496 if (comms) PetscAssertPointer(comms, 3); 497 PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms)); 498 PetscFunctionReturn(PETSC_SUCCESS); 499 } 500 501 PetscErrorCode PCDestroy_MG(PC pc) 502 { 503 PC_MG *mg = (PC_MG *)pc->data; 504 PC_MG_Levels **mglevels = mg->levels; 505 PetscInt i, n; 506 507 PetscFunctionBegin; 508 PetscCall(PCReset_MG(pc)); 509 if (mglevels) { 510 n = mglevels[0]->levels; 511 for (i = 0; i < n; i++) { 512 if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd)); 513 PetscCall(KSPDestroy(&mglevels[i]->smoothu)); 514 PetscCall(KSPDestroy(&mglevels[i]->cr)); 515 PetscCall(PetscFree(mglevels[i])); 516 } 517 PetscCall(PetscFree(mg->levels)); 518 } 519 PetscCall(PetscFree(pc->data)); 520 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 521 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 522 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL)); 523 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", NULL)); 524 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL)); 525 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL)); 526 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL)); 527 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL)); 528 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL)); 529 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL)); 530 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL)); 531 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL)); 532 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL)); 533 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL)); 534 PetscFunctionReturn(PETSC_SUCCESS); 535 } 536 537 /* 538 PCApply_MG - Runs either an additive, multiplicative, Kaskadic 539 or full cycle of multigrid. 540 541 Note: 542 A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 543 */ 544 static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) 545 { 546 PC_MG *mg = (PC_MG *)pc->data; 547 PC_MG_Levels **mglevels = mg->levels; 548 PC tpc; 549 PetscInt levels = mglevels[0]->levels, i; 550 PetscBool changeu, changed, matapp; 551 552 PetscFunctionBegin; 553 matapp = (PetscBool)(B && X); 554 if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply)); 555 /* When the DM is supplying the matrix then it will not exist until here */ 556 for (i = 0; i < levels; i++) { 557 if (!mglevels[i]->A) { 558 PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL)); 559 PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A)); 560 } 561 } 562 563 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 564 PetscCall(PCPreSolveChangeRHS(tpc, &changed)); 565 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 566 PetscCall(PCPreSolveChangeRHS(tpc, &changeu)); 567 if (!changeu && !changed) { 568 if (matapp) { 569 PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 570 mglevels[levels - 1]->B = B; 571 } else { 572 PetscCall(VecDestroy(&mglevels[levels - 1]->b)); 573 mglevels[levels - 1]->b = b; 574 } 575 } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 576 if (matapp) { 577 if (mglevels[levels - 1]->B) { 578 PetscInt N1, N2; 579 PetscBool flg; 580 581 PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1)); 582 PetscCall(MatGetSize(B, NULL, &N2)); 583 PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg)); 584 if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B)); 585 } 586 if (!mglevels[levels - 1]->B) { 587 PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B)); 588 } else { 589 PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN)); 590 } 591 } else { 592 if (!mglevels[levels - 1]->b) { 593 Vec *vec; 594 595 PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL)); 596 mglevels[levels - 1]->b = *vec; 597 PetscCall(PetscFree(vec)); 598 } 599 PetscCall(VecCopy(b, mglevels[levels - 1]->b)); 600 } 601 } 602 if (matapp) { 603 mglevels[levels - 1]->X = X; 604 } else { 605 mglevels[levels - 1]->x = x; 606 } 607 608 /* If coarser Xs are present, it means we have already block applied the PC at least once 609 Reset operators if sizes/type do no match */ 610 if (matapp && levels > 1 && mglevels[levels - 2]->X) { 611 PetscInt Xc, Bc; 612 PetscBool flg; 613 614 PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc)); 615 PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc)); 616 PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg)); 617 if (Xc != Bc || !flg) { 618 PetscCall(MatDestroy(&mglevels[levels - 1]->R)); 619 for (i = 0; i < levels - 1; i++) { 620 PetscCall(MatDestroy(&mglevels[i]->R)); 621 PetscCall(MatDestroy(&mglevels[i]->B)); 622 PetscCall(MatDestroy(&mglevels[i]->X)); 623 } 624 } 625 } 626 627 if (mg->am == PC_MG_MULTIPLICATIVE) { 628 if (matapp) PetscCall(MatZeroEntries(X)); 629 else PetscCall(VecZeroEntries(x)); 630 for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL)); 631 } else if (mg->am == PC_MG_ADDITIVE) { 632 PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp)); 633 } else if (mg->am == PC_MG_KASKADE) { 634 PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp)); 635 } else { 636 PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp)); 637 } 638 if (mg->stageApply) PetscCall(PetscLogStagePop()); 639 if (!changeu && !changed) { 640 if (matapp) { 641 mglevels[levels - 1]->B = NULL; 642 } else { 643 mglevels[levels - 1]->b = NULL; 644 } 645 } 646 PetscFunctionReturn(PETSC_SUCCESS); 647 } 648 649 static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) 650 { 651 PetscFunctionBegin; 652 PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE)); 653 PetscFunctionReturn(PETSC_SUCCESS); 654 } 655 656 static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) 657 { 658 PetscFunctionBegin; 659 PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE)); 660 PetscFunctionReturn(PETSC_SUCCESS); 661 } 662 663 static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) 664 { 665 PetscFunctionBegin; 666 PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE)); 667 PetscFunctionReturn(PETSC_SUCCESS); 668 } 669 670 static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x) 671 { 672 PetscFunctionBegin; 673 PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE)); 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject) 678 { 679 PetscInt levels, cycles; 680 PetscBool flg, flg2; 681 PC_MG *mg = (PC_MG *)pc->data; 682 PC_MG_Levels **mglevels; 683 PCMGType mgtype; 684 PCMGCycleType mgctype; 685 PCMGGalerkinType gtype; 686 PCMGCoarseSpaceType coarseSpaceType; 687 688 PetscFunctionBegin; 689 levels = PetscMax(mg->nlevels, 1); 690 PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options"); 691 PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg)); 692 if (!flg && !mg->levels && pc->dm) { 693 PetscCall(DMGetRefineLevel(pc->dm, &levels)); 694 levels++; 695 mg->usedmfornumberoflevels = PETSC_TRUE; 696 } 697 PetscCall(PCMGSetLevels(pc, levels, NULL)); 698 mglevels = mg->levels; 699 700 mgctype = (PCMGCycleType)mglevels[0]->cycles; 701 PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg)); 702 if (flg) PetscCall(PCMGSetCycleType(pc, mgctype)); 703 coarseSpaceType = mg->coarseSpaceType; 704 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)); 705 if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType)); 706 PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg)); 707 PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg)); 708 flg2 = PETSC_FALSE; 709 PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg)); 710 if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2)); 711 flg = PETSC_FALSE; 712 PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL)); 713 if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc)); 714 PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)>ype, &flg)); 715 if (flg) PetscCall(PCMGSetGalerkin(pc, gtype)); 716 mgtype = mg->am; 717 PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg)); 718 if (flg) PetscCall(PCMGSetType(pc, mgtype)); 719 if (mg->am == PC_MG_MULTIPLICATIVE) { 720 PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg)); 721 if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles)); 722 } 723 flg = PETSC_FALSE; 724 PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL)); 725 if (flg) { 726 PetscInt i; 727 char eventname[128]; 728 729 levels = mglevels[0]->levels; 730 for (i = 0; i < levels; i++) { 731 PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i)); 732 PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup)); 733 PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i)); 734 PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve)); 735 if (i) { 736 PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i)); 737 PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual)); 738 PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i)); 739 PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict)); 740 } 741 } 742 743 if (PetscDefined(USE_LOG)) { 744 const char sname[] = "MG Apply"; 745 746 PetscCall(PetscLogStageGetId(sname, &mg->stageApply)); 747 if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply)); 748 } 749 } 750 PetscOptionsHeadEnd(); 751 /* Check option consistency */ 752 PetscCall(PCMGGetGalerkin(pc, >ype)); 753 PetscCall(PCMGGetAdaptInterpolation(pc, &flg)); 754 PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator"); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 const char *const PCMGTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL}; 759 const char *const PCMGCycleTypes[] = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL}; 760 const char *const PCMGGalerkinTypes[] = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL}; 761 const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL}; 762 763 #include <petscdraw.h> 764 PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) 765 { 766 PC_MG *mg = (PC_MG *)pc->data; 767 PC_MG_Levels **mglevels = mg->levels; 768 PetscInt levels = mglevels ? mglevels[0]->levels : 0, i; 769 PetscBool iascii, isbinary, isdraw; 770 771 PetscFunctionBegin; 772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 775 if (iascii) { 776 const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 777 PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename)); 778 if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, " Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply)); 779 if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 780 PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices\n")); 781 } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 782 PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for pmat\n")); 783 } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 784 PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid matrices for mat\n")); 785 } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 786 PetscCall(PetscViewerASCIIPrintf(viewer, " Using externally compute Galerkin coarse grid matrices\n")); 787 } else { 788 PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid matrices\n")); 789 } 790 if (mg->view) PetscCall((*mg->view)(pc, viewer)); 791 for (i = 0; i < levels; i++) { 792 if (i) { 793 PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 794 } else { 795 PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 796 } 797 PetscCall(PetscViewerASCIIPushTab(viewer)); 798 PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 799 PetscCall(PetscViewerASCIIPopTab(viewer)); 800 if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 801 PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n")); 802 } else if (i) { 803 PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 804 PetscCall(PetscViewerASCIIPushTab(viewer)); 805 PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 806 PetscCall(PetscViewerASCIIPopTab(viewer)); 807 } 808 if (i && mglevels[i]->cr) { 809 PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i)); 810 PetscCall(PetscViewerASCIIPushTab(viewer)); 811 PetscCall(KSPView(mglevels[i]->cr, viewer)); 812 PetscCall(PetscViewerASCIIPopTab(viewer)); 813 } 814 } 815 } else if (isbinary) { 816 for (i = levels - 1; i >= 0; i--) { 817 PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 818 if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 819 } 820 } else if (isdraw) { 821 PetscDraw draw; 822 PetscReal x, w, y, bottom, th; 823 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 824 PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 825 PetscCall(PetscDrawStringGetSize(draw, NULL, &th)); 826 bottom = y - th; 827 for (i = levels - 1; i >= 0; i--) { 828 if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 829 PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 830 PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 831 PetscCall(PetscDrawPopCurrentPoint(draw)); 832 } else { 833 w = 0.5 * PetscMin(1.0 - x, x); 834 PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 835 PetscCall(KSPView(mglevels[i]->smoothd, viewer)); 836 PetscCall(PetscDrawPopCurrentPoint(draw)); 837 PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 838 PetscCall(KSPView(mglevels[i]->smoothu, viewer)); 839 PetscCall(PetscDrawPopCurrentPoint(draw)); 840 } 841 PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL)); 842 bottom -= th; 843 } 844 } 845 PetscFunctionReturn(PETSC_SUCCESS); 846 } 847 848 #include <petsc/private/kspimpl.h> 849 850 /* 851 Calls setup for the KSP on each level 852 */ 853 PetscErrorCode PCSetUp_MG(PC pc) 854 { 855 PC_MG *mg = (PC_MG *)pc->data; 856 PC_MG_Levels **mglevels = mg->levels; 857 PetscInt i, n; 858 PC cpc; 859 PetscBool dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE; 860 Mat dA, dB; 861 Vec tvec; 862 DM *dms; 863 PetscViewer viewer = NULL; 864 PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE; 865 PetscBool adaptInterpolation = mg->adaptInterpolation; 866 867 PetscFunctionBegin; 868 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up"); 869 n = mglevels[0]->levels; 870 /* FIX: Move this to PCSetFromOptions_MG? */ 871 if (mg->usedmfornumberoflevels) { 872 PetscInt levels; 873 PetscCall(DMGetRefineLevel(pc->dm, &levels)); 874 levels++; 875 if (levels > n) { /* the problem is now being solved on a finer grid */ 876 PetscCall(PCMGSetLevels(pc, levels, NULL)); 877 n = levels; 878 PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 879 mglevels = mg->levels; 880 } 881 } 882 883 /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 884 /* so use those from global PC */ 885 /* Is this what we always want? What if user wants to keep old one? */ 886 PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset)); 887 if (opsset) { 888 Mat mmat; 889 PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat)); 890 if (mmat == pc->pmat) opsset = PETSC_FALSE; 891 } 892 /* fine grid smoother inherits the reuse-pc flag */ 893 PetscCall(KSPGetPC(mglevels[n - 1]->smoothd, &cpc)); 894 cpc->reusepreconditioner = pc->reusepreconditioner; 895 PetscCall(KSPGetPC(mglevels[n - 1]->smoothu, &cpc)); 896 cpc->reusepreconditioner = pc->reusepreconditioner; 897 898 /* Create CR solvers */ 899 PetscCall(PCMGGetAdaptCR(pc, &doCR)); 900 if (doCR) { 901 const char *prefix; 902 903 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 904 for (i = 1; i < n; ++i) { 905 PC ipc, cr; 906 char crprefix[128]; 907 908 PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr)); 909 PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel)); 910 PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 911 PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i)); 912 PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 913 PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 914 PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 915 PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 916 PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 917 PetscCall(KSPGetPC(mglevels[i]->cr, &ipc)); 918 919 PetscCall(PCSetType(ipc, PCCOMPOSITE)); 920 PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 921 PetscCall(PCCompositeAddPCType(ipc, PCSOR)); 922 PetscCall(CreateCR_Private(pc, i, &cr)); 923 PetscCall(PCCompositeAddPC(ipc, cr)); 924 PetscCall(PCDestroy(&cr)); 925 926 PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd)); 927 PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 928 PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i)); 929 PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 930 } 931 } 932 933 if (!opsset) { 934 PetscCall(PCGetUseAmat(pc, &use_amat)); 935 if (use_amat) { 936 PetscCall(PetscInfo(pc, "Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n")); 937 PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat)); 938 } else { 939 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")); 940 PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat)); 941 } 942 } 943 944 for (i = n - 1; i > 0; i--) { 945 if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 946 missinginterpolate = PETSC_TRUE; 947 break; 948 } 949 } 950 951 PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB)); 952 if (dA == dB) dAeqdB = PETSC_TRUE; 953 if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) { 954 needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */ 955 } 956 957 if (pc->dm && !pc->setupcalled) { 958 /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 959 PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm)); 960 PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE)); 961 if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) { 962 PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm)); 963 PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE)); 964 } 965 if (mglevels[n - 1]->cr) { 966 PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm)); 967 PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE)); 968 } 969 } 970 971 /* 972 Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 973 Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 974 */ 975 if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 976 /* first see if we can compute a coarse space */ 977 if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) { 978 for (i = n - 2; i > -1; i--) { 979 if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) { 980 PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace)); 981 PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace)); 982 } 983 } 984 } else { /* construct the interpolation from the DMs */ 985 Mat p; 986 Vec rscale; 987 PetscCall(PetscMalloc1(n, &dms)); 988 dms[n - 1] = pc->dm; 989 /* Separately create them so we do not get DMKSP interference between levels */ 990 for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i])); 991 for (i = n - 2; i > -1; i--) { 992 DMKSP kdm; 993 PetscBool dmhasrestrict, dmhasinject; 994 PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i])); 995 if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE)); 996 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 997 PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i])); 998 if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE)); 999 } 1000 if (mglevels[i]->cr) { 1001 PetscCall(KSPSetDM(mglevels[i]->cr, dms[i])); 1002 if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE)); 1003 } 1004 PetscCall(DMGetDMKSPWrite(dms[i], &kdm)); 1005 /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 1006 * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 1007 kdm->ops->computerhs = NULL; 1008 kdm->rhsctx = NULL; 1009 if (!mglevels[i + 1]->interpolate) { 1010 PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale)); 1011 PetscCall(PCMGSetInterpolation(pc, i + 1, p)); 1012 if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale)); 1013 PetscCall(VecDestroy(&rscale)); 1014 PetscCall(MatDestroy(&p)); 1015 } 1016 PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict)); 1017 if (dmhasrestrict && !mglevels[i + 1]->restrct) { 1018 PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p)); 1019 PetscCall(PCMGSetRestriction(pc, i + 1, p)); 1020 PetscCall(MatDestroy(&p)); 1021 } 1022 PetscCall(DMHasCreateInjection(dms[i], &dmhasinject)); 1023 if (dmhasinject && !mglevels[i + 1]->inject) { 1024 PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p)); 1025 PetscCall(PCMGSetInjection(pc, i + 1, p)); 1026 PetscCall(MatDestroy(&p)); 1027 } 1028 } 1029 1030 for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i])); 1031 PetscCall(PetscFree(dms)); 1032 } 1033 } 1034 1035 if (mg->galerkin < PC_MG_GALERKIN_NONE) { 1036 Mat A, B; 1037 PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE; 1038 MatReuse reuse = MAT_INITIAL_MATRIX; 1039 1040 if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE; 1041 if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE; 1042 if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 1043 for (i = n - 2; i > -1; i--) { 1044 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"); 1045 if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct)); 1046 if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate)); 1047 if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B)); 1048 if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A)); 1049 if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B)); 1050 /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 1051 if (!doA && dAeqdB) { 1052 if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B)); 1053 A = B; 1054 } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 1055 PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL)); 1056 PetscCall(PetscObjectReference((PetscObject)A)); 1057 } 1058 if (!doB && dAeqdB) { 1059 if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A)); 1060 B = A; 1061 } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 1062 PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B)); 1063 PetscCall(PetscObjectReference((PetscObject)B)); 1064 } 1065 if (reuse == MAT_INITIAL_MATRIX) { 1066 PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B)); 1067 PetscCall(PetscObjectDereference((PetscObject)A)); 1068 PetscCall(PetscObjectDereference((PetscObject)B)); 1069 } 1070 dA = A; 1071 dB = B; 1072 } 1073 } 1074 1075 /* Adapt interpolation matrices */ 1076 if (adaptInterpolation) { 1077 for (i = 0; i < n; ++i) { 1078 if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace)); 1079 if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace)); 1080 } 1081 for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i)); 1082 } 1083 1084 if (needRestricts && pc->dm) { 1085 for (i = n - 2; i >= 0; i--) { 1086 DM dmfine, dmcoarse; 1087 Mat Restrict, Inject; 1088 Vec rscale; 1089 PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine)); 1090 PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse)); 1091 PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict)); 1092 PetscCall(PCMGGetRScale(pc, i + 1, &rscale)); 1093 PetscCall(PCMGGetInjection(pc, i + 1, &Inject)); 1094 PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse)); 1095 } 1096 } 1097 1098 if (!pc->setupcalled) { 1099 for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd)); 1100 for (i = 1; i < n; i++) { 1101 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu)); 1102 if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr)); 1103 } 1104 /* insure that if either interpolation or restriction is set the other one is set */ 1105 for (i = 1; i < n; i++) { 1106 PetscCall(PCMGGetInterpolation(pc, i, NULL)); 1107 PetscCall(PCMGGetRestriction(pc, i, NULL)); 1108 } 1109 for (i = 0; i < n - 1; i++) { 1110 if (!mglevels[i]->b) { 1111 Vec *vec; 1112 PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL)); 1113 PetscCall(PCMGSetRhs(pc, i, *vec)); 1114 PetscCall(VecDestroy(vec)); 1115 PetscCall(PetscFree(vec)); 1116 } 1117 if (!mglevels[i]->r && i) { 1118 PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 1119 PetscCall(PCMGSetR(pc, i, tvec)); 1120 PetscCall(VecDestroy(&tvec)); 1121 } 1122 if (!mglevels[i]->x) { 1123 PetscCall(VecDuplicate(mglevels[i]->b, &tvec)); 1124 PetscCall(PCMGSetX(pc, i, tvec)); 1125 PetscCall(VecDestroy(&tvec)); 1126 } 1127 if (doCR) { 1128 PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx)); 1129 PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb)); 1130 PetscCall(VecZeroEntries(mglevels[i]->crb)); 1131 } 1132 } 1133 if (n != 1 && !mglevels[n - 1]->r) { 1134 /* PCMGSetR() on the finest level if user did not supply it */ 1135 Vec *vec; 1136 PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL)); 1137 PetscCall(PCMGSetR(pc, n - 1, *vec)); 1138 PetscCall(VecDestroy(vec)); 1139 PetscCall(PetscFree(vec)); 1140 } 1141 if (doCR) { 1142 PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx)); 1143 PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb)); 1144 PetscCall(VecZeroEntries(mglevels[n - 1]->crb)); 1145 } 1146 } 1147 1148 if (pc->dm) { 1149 /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 1150 for (i = 0; i < n - 1; i++) { 1151 if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1152 } 1153 } 1154 // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g., 1155 // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply. 1156 if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 1157 1158 for (i = 1; i < n; i++) { 1159 if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1160 /* if doing only down then initial guess is zero */ 1161 PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE)); 1162 } 1163 if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 1164 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1165 PetscCall(KSPSetUp(mglevels[i]->smoothd)); 1166 if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 1167 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1168 if (!mglevels[i]->residual) { 1169 Mat mat; 1170 PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 1171 PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat)); 1172 } 1173 if (!mglevels[i]->residualtranspose) { 1174 Mat mat; 1175 PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL)); 1176 PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat)); 1177 } 1178 } 1179 for (i = 1; i < n; i++) { 1180 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1181 Mat downmat, downpmat; 1182 1183 /* check if operators have been set for up, if not use down operators to set them */ 1184 PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL)); 1185 if (!opsset) { 1186 PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 1187 PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat)); 1188 } 1189 1190 PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE)); 1191 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1192 PetscCall(KSPSetUp(mglevels[i]->smoothu)); 1193 if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR; 1194 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1195 } 1196 if (mglevels[i]->cr) { 1197 Mat downmat, downpmat; 1198 1199 /* check if operators have been set for up, if not use down operators to set them */ 1200 PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL)); 1201 if (!opsset) { 1202 PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat)); 1203 PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat)); 1204 } 1205 1206 PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 1207 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1208 PetscCall(KSPSetUp(mglevels[i]->cr)); 1209 if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR; 1210 if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0)); 1211 } 1212 } 1213 1214 if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1215 PetscCall(KSPSetUp(mglevels[0]->smoothd)); 1216 if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR; 1217 if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0)); 1218 1219 /* 1220 Dump the interpolation/restriction matrices plus the 1221 Jacobian/stiffness on each level. This allows MATLAB users to 1222 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1223 1224 Only support one or the other at the same time. 1225 */ 1226 #if defined(PETSC_USE_SOCKET_VIEWER) 1227 PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL)); 1228 if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1229 dump = PETSC_FALSE; 1230 #endif 1231 PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL)); 1232 if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1233 1234 if (viewer) { 1235 for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer)); 1236 for (i = 0; i < n; i++) { 1237 PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc)); 1238 PetscCall(MatView(pc->mat, viewer)); 1239 } 1240 } 1241 PetscFunctionReturn(PETSC_SUCCESS); 1242 } 1243 1244 PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 1245 { 1246 PC_MG *mg = (PC_MG *)pc->data; 1247 1248 PetscFunctionBegin; 1249 *levels = mg->nlevels; 1250 PetscFunctionReturn(PETSC_SUCCESS); 1251 } 1252 1253 /*@ 1254 PCMGGetLevels - Gets the number of levels to use with `PCMG`. 1255 1256 Not Collective 1257 1258 Input Parameter: 1259 . pc - the preconditioner context 1260 1261 Output Parameter: 1262 . levels - the number of levels 1263 1264 Level: advanced 1265 1266 .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()` 1267 @*/ 1268 PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) 1269 { 1270 PetscFunctionBegin; 1271 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1272 PetscAssertPointer(levels, 2); 1273 *levels = 0; 1274 PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels)); 1275 PetscFunctionReturn(PETSC_SUCCESS); 1276 } 1277 1278 /*@ 1279 PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy 1280 1281 Input Parameter: 1282 . pc - the preconditioner context 1283 1284 Output Parameters: 1285 + gc - grid complexity = sum_i(n_i) / n_0 1286 - oc - operator complexity = sum_i(nnz_i) / nnz_0 1287 1288 Level: advanced 1289 1290 Note: 1291 This is often call the operator complexity in multigrid literature 1292 1293 .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()` 1294 @*/ 1295 PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) 1296 { 1297 PC_MG *mg = (PC_MG *)pc->data; 1298 PC_MG_Levels **mglevels = mg->levels; 1299 PetscInt lev, N; 1300 PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1301 MatInfo info; 1302 1303 PetscFunctionBegin; 1304 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1305 if (gc) PetscAssertPointer(gc, 2); 1306 if (oc) PetscAssertPointer(oc, 3); 1307 if (!pc->setupcalled) { 1308 if (gc) *gc = 0; 1309 if (oc) *oc = 0; 1310 PetscFunctionReturn(PETSC_SUCCESS); 1311 } 1312 PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels"); 1313 for (lev = 0; lev < mg->nlevels; lev++) { 1314 Mat dB; 1315 PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB)); 1316 PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */ 1317 PetscCall(MatGetSize(dB, &N, NULL)); 1318 sgc += N; 1319 soc += info.nz_used; 1320 if (lev == mg->nlevels - 1) { 1321 nnz0 = info.nz_used; 1322 n0 = N; 1323 } 1324 } 1325 PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available"); 1326 *gc = (PetscReal)(sgc / n0); 1327 if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0); 1328 PetscFunctionReturn(PETSC_SUCCESS); 1329 } 1330 1331 /*@ 1332 PCMGSetType - Determines the form of multigrid to use, either 1333 multiplicative, additive, full, or the Kaskade algorithm. 1334 1335 Logically Collective 1336 1337 Input Parameters: 1338 + pc - the preconditioner context 1339 - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE` 1340 1341 Options Database Key: 1342 . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade 1343 1344 Level: advanced 1345 1346 .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType` 1347 @*/ 1348 PetscErrorCode PCMGSetType(PC pc, PCMGType form) 1349 { 1350 PC_MG *mg = (PC_MG *)pc->data; 1351 1352 PetscFunctionBegin; 1353 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1354 PetscValidLogicalCollectiveEnum(pc, form, 2); 1355 mg->am = form; 1356 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1357 else pc->ops->applyrichardson = NULL; 1358 PetscFunctionReturn(PETSC_SUCCESS); 1359 } 1360 1361 /*@ 1362 PCMGGetType - Finds the form of multigrid the `PCMG` is using multiplicative, additive, full, or the Kaskade algorithm. 1363 1364 Logically Collective 1365 1366 Input Parameter: 1367 . pc - the preconditioner context 1368 1369 Output Parameter: 1370 . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType` 1371 1372 Level: advanced 1373 1374 .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()` 1375 @*/ 1376 PetscErrorCode PCMGGetType(PC pc, PCMGType *type) 1377 { 1378 PC_MG *mg = (PC_MG *)pc->data; 1379 1380 PetscFunctionBegin; 1381 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1382 *type = mg->am; 1383 PetscFunctionReturn(PETSC_SUCCESS); 1384 } 1385 1386 /*@ 1387 PCMGSetCycleType - Sets the type cycles to use. Use `PCMGSetCycleTypeOnLevel()` for more 1388 complicated cycling. 1389 1390 Logically Collective 1391 1392 Input Parameters: 1393 + pc - the multigrid context 1394 - n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 1395 1396 Options Database Key: 1397 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1398 1399 Level: advanced 1400 1401 .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType` 1402 @*/ 1403 PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) 1404 { 1405 PC_MG *mg = (PC_MG *)pc->data; 1406 PC_MG_Levels **mglevels = mg->levels; 1407 PetscInt i, levels; 1408 1409 PetscFunctionBegin; 1410 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1411 PetscValidLogicalCollectiveEnum(pc, n, 2); 1412 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1413 levels = mglevels[0]->levels; 1414 for (i = 0; i < levels; i++) mglevels[i]->cycles = n; 1415 PetscFunctionReturn(PETSC_SUCCESS); 1416 } 1417 1418 /*@ 1419 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1420 of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE` 1421 1422 Logically Collective 1423 1424 Input Parameters: 1425 + pc - the multigrid context 1426 - n - number of cycles (default is 1) 1427 1428 Options Database Key: 1429 . -pc_mg_multiplicative_cycles n - set the number of cycles 1430 1431 Level: advanced 1432 1433 Note: 1434 This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()` 1435 1436 .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType` 1437 @*/ 1438 PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) 1439 { 1440 PC_MG *mg = (PC_MG *)pc->data; 1441 1442 PetscFunctionBegin; 1443 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1444 PetscValidLogicalCollectiveInt(pc, n, 2); 1445 mg->cyclesperpcapply = n; 1446 PetscFunctionReturn(PETSC_SUCCESS); 1447 } 1448 1449 /* 1450 Since the finest level KSP shares the original matrix (of the entire system), it's preconditioner 1451 should not be updated if the whole PC is supposed to reuse the preconditioner 1452 */ 1453 static PetscErrorCode PCSetReusePreconditioner_MG(PC pc, PetscBool flag) 1454 { 1455 PC_MG *mg = (PC_MG *)pc->data; 1456 PC_MG_Levels **mglevels = mg->levels; 1457 PetscInt levels; 1458 PC tpc; 1459 1460 PetscFunctionBegin; 1461 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1462 PetscValidLogicalCollectiveBool(pc, flag, 2); 1463 if (mglevels) { 1464 levels = mglevels[0]->levels; 1465 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc)); 1466 tpc->reusepreconditioner = flag; 1467 PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc)); 1468 tpc->reusepreconditioner = flag; 1469 } 1470 PetscFunctionReturn(PETSC_SUCCESS); 1471 } 1472 1473 static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) 1474 { 1475 PC_MG *mg = (PC_MG *)pc->data; 1476 1477 PetscFunctionBegin; 1478 mg->galerkin = use; 1479 PetscFunctionReturn(PETSC_SUCCESS); 1480 } 1481 1482 /*@ 1483 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 1484 finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1485 1486 Logically Collective 1487 1488 Input Parameters: 1489 + pc - the multigrid context 1490 - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE` 1491 1492 Options Database Key: 1493 . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1494 1495 Level: intermediate 1496 1497 Note: 1498 Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not 1499 use the `PCMG` construction of the coarser grids. 1500 1501 .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType` 1502 @*/ 1503 PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) 1504 { 1505 PetscFunctionBegin; 1506 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1507 PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use)); 1508 PetscFunctionReturn(PETSC_SUCCESS); 1509 } 1510 1511 /*@ 1512 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i 1513 1514 Not Collective 1515 1516 Input Parameter: 1517 . pc - the multigrid context 1518 1519 Output Parameter: 1520 . galerkin - one of `PC_MG_GALERKIN_BOTH`,`PC_MG_GALERKIN_PMAT`,`PC_MG_GALERKIN_MAT`, `PC_MG_GALERKIN_NONE`, or `PC_MG_GALERKIN_EXTERNAL` 1521 1522 Level: intermediate 1523 1524 .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType` 1525 @*/ 1526 PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) 1527 { 1528 PC_MG *mg = (PC_MG *)pc->data; 1529 1530 PetscFunctionBegin; 1531 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1532 *galerkin = mg->galerkin; 1533 PetscFunctionReturn(PETSC_SUCCESS); 1534 } 1535 1536 static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) 1537 { 1538 PC_MG *mg = (PC_MG *)pc->data; 1539 1540 PetscFunctionBegin; 1541 mg->adaptInterpolation = adapt; 1542 PetscFunctionReturn(PETSC_SUCCESS); 1543 } 1544 1545 static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) 1546 { 1547 PC_MG *mg = (PC_MG *)pc->data; 1548 1549 PetscFunctionBegin; 1550 *adapt = mg->adaptInterpolation; 1551 PetscFunctionReturn(PETSC_SUCCESS); 1552 } 1553 1554 static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) 1555 { 1556 PC_MG *mg = (PC_MG *)pc->data; 1557 1558 PetscFunctionBegin; 1559 mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE; 1560 mg->coarseSpaceType = ctype; 1561 PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH)); 1562 PetscFunctionReturn(PETSC_SUCCESS); 1563 } 1564 1565 static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) 1566 { 1567 PC_MG *mg = (PC_MG *)pc->data; 1568 1569 PetscFunctionBegin; 1570 *ctype = mg->coarseSpaceType; 1571 PetscFunctionReturn(PETSC_SUCCESS); 1572 } 1573 1574 static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) 1575 { 1576 PC_MG *mg = (PC_MG *)pc->data; 1577 1578 PetscFunctionBegin; 1579 mg->compatibleRelaxation = cr; 1580 PetscFunctionReturn(PETSC_SUCCESS); 1581 } 1582 1583 static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) 1584 { 1585 PC_MG *mg = (PC_MG *)pc->data; 1586 1587 PetscFunctionBegin; 1588 *cr = mg->compatibleRelaxation; 1589 PetscFunctionReturn(PETSC_SUCCESS); 1590 } 1591 1592 /*@ 1593 PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space. 1594 1595 Adapts or creates the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 1596 1597 Logically Collective 1598 1599 Input Parameters: 1600 + pc - the multigrid context 1601 - ctype - the type of coarse space 1602 1603 Options Database Keys: 1604 + -pc_mg_adapt_interp_n <int> - The number of modes to use 1605 - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw` 1606 1607 Level: intermediate 1608 1609 Note: 1610 Requires a `DM` with specific functionality be attached to the `PC`. 1611 1612 .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM` 1613 @*/ 1614 PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) 1615 { 1616 PetscFunctionBegin; 1617 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1618 PetscValidLogicalCollectiveEnum(pc, ctype, 2); 1619 PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype)); 1620 PetscFunctionReturn(PETSC_SUCCESS); 1621 } 1622 1623 /*@ 1624 PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space. 1625 1626 Not Collective 1627 1628 Input Parameter: 1629 . pc - the multigrid context 1630 1631 Output Parameter: 1632 . ctype - the type of coarse space 1633 1634 Level: intermediate 1635 1636 .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()` 1637 @*/ 1638 PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) 1639 { 1640 PetscFunctionBegin; 1641 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1642 PetscAssertPointer(ctype, 2); 1643 PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype)); 1644 PetscFunctionReturn(PETSC_SUCCESS); 1645 } 1646 1647 /* MATT: REMOVE? */ 1648 /*@ 1649 PCMGSetAdaptInterpolation - Adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 1650 1651 Logically Collective 1652 1653 Input Parameters: 1654 + pc - the multigrid context 1655 - adapt - flag for adaptation of the interpolator 1656 1657 Options Database Keys: 1658 + -pc_mg_adapt_interp - Turn on adaptation 1659 . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1660 - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1661 1662 Level: intermediate 1663 1664 .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1665 @*/ 1666 PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) 1667 { 1668 PetscFunctionBegin; 1669 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1670 PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt)); 1671 PetscFunctionReturn(PETSC_SUCCESS); 1672 } 1673 1674 /*@ 1675 PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, 1676 and thus accurately interpolated. 1677 1678 Not Collective 1679 1680 Input Parameter: 1681 . pc - the multigrid context 1682 1683 Output Parameter: 1684 . adapt - flag for adaptation of the interpolator 1685 1686 Level: intermediate 1687 1688 .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1689 @*/ 1690 PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) 1691 { 1692 PetscFunctionBegin; 1693 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1694 PetscAssertPointer(adapt, 2); 1695 PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt)); 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 /*@ 1700 PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 1701 1702 Logically Collective 1703 1704 Input Parameters: 1705 + pc - the multigrid context 1706 - cr - flag for compatible relaxation 1707 1708 Options Database Key: 1709 . -pc_mg_adapt_cr - Turn on compatible relaxation 1710 1711 Level: intermediate 1712 1713 .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1714 @*/ 1715 PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) 1716 { 1717 PetscFunctionBegin; 1718 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1719 PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr)); 1720 PetscFunctionReturn(PETSC_SUCCESS); 1721 } 1722 1723 /*@ 1724 PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 1725 1726 Not Collective 1727 1728 Input Parameter: 1729 . pc - the multigrid context 1730 1731 Output Parameter: 1732 . cr - flag for compatible relaxaion 1733 1734 Level: intermediate 1735 1736 .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1737 @*/ 1738 PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) 1739 { 1740 PetscFunctionBegin; 1741 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1742 PetscAssertPointer(cr, 2); 1743 PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr)); 1744 PetscFunctionReturn(PETSC_SUCCESS); 1745 } 1746 1747 /*@ 1748 PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1749 on all levels. Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of 1750 pre- and post-smoothing steps. 1751 1752 Logically Collective 1753 1754 Input Parameters: 1755 + pc - the multigrid context 1756 - n - the number of smoothing steps 1757 1758 Options Database Key: 1759 . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 1760 1761 Level: advanced 1762 1763 Note: 1764 This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid. 1765 1766 .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()` 1767 @*/ 1768 PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) 1769 { 1770 PC_MG *mg = (PC_MG *)pc->data; 1771 PC_MG_Levels **mglevels = mg->levels; 1772 PetscInt i, levels; 1773 1774 PetscFunctionBegin; 1775 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1776 PetscValidLogicalCollectiveInt(pc, n, 2); 1777 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1778 levels = mglevels[0]->levels; 1779 1780 for (i = 1; i < levels; i++) { 1781 PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 1782 PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n)); 1783 mg->default_smoothu = n; 1784 mg->default_smoothd = n; 1785 } 1786 PetscFunctionReturn(PETSC_SUCCESS); 1787 } 1788 1789 /*@ 1790 PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels 1791 and adds the suffix _up to the options name 1792 1793 Logically Collective 1794 1795 Input Parameter: 1796 . pc - the preconditioner context 1797 1798 Options Database Key: 1799 . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1800 1801 Level: advanced 1802 1803 Note: 1804 This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid. 1805 1806 .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()` 1807 @*/ 1808 PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1809 { 1810 PC_MG *mg = (PC_MG *)pc->data; 1811 PC_MG_Levels **mglevels = mg->levels; 1812 PetscInt i, levels; 1813 KSP subksp; 1814 1815 PetscFunctionBegin; 1816 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1817 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling"); 1818 levels = mglevels[0]->levels; 1819 1820 for (i = 1; i < levels; i++) { 1821 const char *prefix = NULL; 1822 /* make sure smoother up and down are different */ 1823 PetscCall(PCMGGetSmootherUp(pc, i, &subksp)); 1824 PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix)); 1825 PetscCall(KSPSetOptionsPrefix(subksp, prefix)); 1826 PetscCall(KSPAppendOptionsPrefix(subksp, "up_")); 1827 } 1828 PetscFunctionReturn(PETSC_SUCCESS); 1829 } 1830 1831 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1832 static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) 1833 { 1834 PC_MG *mg = (PC_MG *)pc->data; 1835 PC_MG_Levels **mglevels = mg->levels; 1836 Mat *mat; 1837 PetscInt l; 1838 1839 PetscFunctionBegin; 1840 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 1841 PetscCall(PetscMalloc1(mg->nlevels, &mat)); 1842 for (l = 1; l < mg->nlevels; l++) { 1843 mat[l - 1] = mglevels[l]->interpolate; 1844 PetscCall(PetscObjectReference((PetscObject)mat[l - 1])); 1845 } 1846 *num_levels = mg->nlevels; 1847 *interpolations = mat; 1848 PetscFunctionReturn(PETSC_SUCCESS); 1849 } 1850 1851 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1852 static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) 1853 { 1854 PC_MG *mg = (PC_MG *)pc->data; 1855 PC_MG_Levels **mglevels = mg->levels; 1856 PetscInt l; 1857 Mat *mat; 1858 1859 PetscFunctionBegin; 1860 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 1861 PetscCall(PetscMalloc1(mg->nlevels, &mat)); 1862 for (l = 0; l < mg->nlevels - 1; l++) { 1863 PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l])); 1864 PetscCall(PetscObjectReference((PetscObject)mat[l])); 1865 } 1866 *num_levels = mg->nlevels; 1867 *coarseOperators = mat; 1868 PetscFunctionReturn(PETSC_SUCCESS); 1869 } 1870 1871 /*@C 1872 PCMGRegisterCoarseSpaceConstructor - Adds a method to the `PCMG` package for coarse space construction. 1873 1874 Not Collective, No Fortran Support 1875 1876 Input Parameters: 1877 + name - name of the constructor 1878 - function - constructor routine, see `PCMGCoarseSpaceConstructorFn` 1879 1880 Level: advanced 1881 1882 Developer Notes: 1883 This does not appear to be used anywhere 1884 1885 .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()` 1886 @*/ 1887 PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function) 1888 { 1889 PetscFunctionBegin; 1890 PetscCall(PCInitializePackage()); 1891 PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function)); 1892 PetscFunctionReturn(PETSC_SUCCESS); 1893 } 1894 1895 /*@C 1896 PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1897 1898 Not Collective, No Fortran Support 1899 1900 Input Parameter: 1901 . name - name of the constructor 1902 1903 Output Parameter: 1904 . function - constructor routine 1905 1906 Level: advanced 1907 1908 .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()` 1909 @*/ 1910 PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function) 1911 { 1912 PetscFunctionBegin; 1913 PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function)); 1914 PetscFunctionReturn(PETSC_SUCCESS); 1915 } 1916 1917 /*MC 1918 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1919 information about the coarser grid matrices and restriction/interpolation operators. 1920 1921 Options Database Keys: 1922 + -pc_mg_levels <nlevels> - number of levels including finest 1923 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1924 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1925 . -pc_mg_log - log information about time spent on each level of the solver 1926 . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 1927 . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1928 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1929 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1930 to a `PETSCVIEWERSOCKET` for reading from MATLAB. 1931 - -pc_mg_dump_binary -dumps the matrices for each level and the restriction/interpolation matrices 1932 to the binary output file called binaryoutput 1933 1934 Level: intermediate 1935 1936 Notes: 1937 The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard 1938 options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`, 1939 and the finest where `-mg_fine_` can override `-mg_levels_`. One can set different preconditioners etc on specific levels with the prefix 1940 `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example 1941 .vb 1942 -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor 1943 .ve 1944 These options also work for controlling the smoothers etc inside `PCGAMG` 1945 1946 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 1947 1948 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1949 1950 When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 1951 is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 1952 (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 1953 residual is computed at the end of each cycle. 1954 1955 .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE` 1956 `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`, 1957 `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`, 1958 `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, 1959 `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`, 1960 `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()` 1961 M*/ 1962 1963 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1964 { 1965 PC_MG *mg; 1966 1967 PetscFunctionBegin; 1968 PetscCall(PetscNew(&mg)); 1969 pc->data = mg; 1970 mg->nlevels = -1; 1971 mg->am = PC_MG_MULTIPLICATIVE; 1972 mg->galerkin = PC_MG_GALERKIN_NONE; 1973 mg->adaptInterpolation = PETSC_FALSE; 1974 mg->Nc = -1; 1975 mg->eigenvalue = -1; 1976 1977 pc->useAmat = PETSC_TRUE; 1978 1979 pc->ops->apply = PCApply_MG; 1980 pc->ops->applytranspose = PCApplyTranspose_MG; 1981 pc->ops->matapply = PCMatApply_MG; 1982 pc->ops->matapplytranspose = PCMatApplyTranspose_MG; 1983 pc->ops->setup = PCSetUp_MG; 1984 pc->ops->reset = PCReset_MG; 1985 pc->ops->destroy = PCDestroy_MG; 1986 pc->ops->setfromoptions = PCSetFromOptions_MG; 1987 pc->ops->view = PCView_MG; 1988 1989 PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue)); 1990 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG)); 1991 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", PCSetReusePreconditioner_MG)); 1992 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG)); 1993 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG)); 1994 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG)); 1995 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG)); 1996 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG)); 1997 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG)); 1998 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG)); 1999 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG)); 2000 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG)); 2001 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG)); 2002 PetscFunctionReturn(PETSC_SUCCESS); 2003 } 2004