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