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