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