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) CHKERRQ(PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0)); 23 if (!transpose) { 24 if (matapp) { 25 CHKERRQ(KSPMatSolve(mglevels->smoothd,mglevels->B,mglevels->X)); /* pre-smooth */ 26 CHKERRQ(KSPCheckSolve(mglevels->smoothd,pc,NULL)); 27 } else { 28 CHKERRQ(KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x)); /* pre-smooth */ 29 CHKERRQ(KSPCheckSolve(mglevels->smoothd,pc,mglevels->x)); 30 } 31 } else { 32 PetscCheck(!matapp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Not supported"); 33 CHKERRQ(KSPSolveTranspose(mglevels->smoothu,mglevels->b,mglevels->x)); /* transpose of post-smooth */ 34 CHKERRQ(KSPCheckSolve(mglevels->smoothu,pc,mglevels->x)); 35 } 36 if (mglevels->eventsmoothsolve) CHKERRQ(PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0)); 37 if (mglevels->level) { /* not the coarsest grid */ 38 if (mglevels->eventresidual) CHKERRQ(PetscLogEventBegin(mglevels->eventresidual,0,0,0,0)); 39 if (matapp && !mglevels->R) { 40 CHKERRQ(MatDuplicate(mglevels->B,MAT_DO_NOT_COPY_VALUES,&mglevels->R)); 41 } 42 if (!transpose) { 43 if (matapp) CHKERRQ((*mglevels->matresidual)(mglevels->A,mglevels->B,mglevels->X,mglevels->R)); 44 else CHKERRQ((*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r)); 45 } else { 46 if (matapp) CHKERRQ((*mglevels->matresidualtranspose)(mglevels->A,mglevels->B,mglevels->X,mglevels->R)); 47 else CHKERRQ((*mglevels->residualtranspose)(mglevels->A,mglevels->b,mglevels->x,mglevels->r)); 48 } 49 if (mglevels->eventresidual) CHKERRQ(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 CHKERRQ(VecNorm(mglevels->r,NORM_2,&rnorm)); 55 if (rnorm <= mg->ttol) { 56 if (rnorm < mg->abstol) { 57 *reason = PCRICHARDSON_CONVERGED_ATOL; 58 CHKERRQ(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 CHKERRQ(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) CHKERRQ(PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0)); 69 if (!transpose) { 70 if (matapp) CHKERRQ(MatMatRestrict(mglevels->restrct,mglevels->R,&mgc->B)); 71 else CHKERRQ(MatRestrict(mglevels->restrct,mglevels->r,mgc->b)); 72 } else { 73 if (matapp) CHKERRQ(MatMatRestrict(mglevels->interpolate,mglevels->R,&mgc->B)); 74 else CHKERRQ(MatRestrict(mglevels->interpolate,mglevels->r,mgc->b)); 75 } 76 if (mglevels->eventinterprestrict) CHKERRQ(PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0)); 77 if (matapp) { 78 if (!mgc->X) { 79 CHKERRQ(MatDuplicate(mgc->B,MAT_DO_NOT_COPY_VALUES,&mgc->X)); 80 } else { 81 CHKERRQ(MatZeroEntries(mgc->X)); 82 } 83 } else { 84 CHKERRQ(VecZeroEntries(mgc->x)); 85 } 86 while (cycles--) { 87 CHKERRQ(PCMGMCycle_Private(pc,mglevelsin-1,transpose,matapp,reason)); 88 } 89 if (mglevels->eventinterprestrict) CHKERRQ(PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0)); 90 if (!transpose) { 91 if (matapp) CHKERRQ(MatMatInterpolateAdd(mglevels->interpolate,mgc->X,mglevels->X,&mglevels->X)); 92 else CHKERRQ(MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x)); 93 } else { 94 CHKERRQ(MatInterpolateAdd(mglevels->restrct,mgc->x,mglevels->x,mglevels->x)); 95 } 96 if (mglevels->eventinterprestrict) CHKERRQ(PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0)); 97 if (mglevels->eventsmoothsolve) CHKERRQ(PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0)); 98 if (!transpose) { 99 if (matapp) { 100 CHKERRQ(KSPMatSolve(mglevels->smoothu,mglevels->B,mglevels->X)); /* post smooth */ 101 CHKERRQ(KSPCheckSolve(mglevels->smoothu,pc,NULL)); 102 } else { 103 CHKERRQ(KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x)); /* post smooth */ 104 CHKERRQ(KSPCheckSolve(mglevels->smoothu,pc,mglevels->x)); 105 } 106 } else { 107 PetscCheck(!matapp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Not supported"); 108 CHKERRQ(KSPSolveTranspose(mglevels->smoothd,mglevels->b,mglevels->x)); /* post smooth */ 109 CHKERRQ(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 CHKERRQ(VecCopy(mglevels->x, mglevels->crx)); 115 CHKERRQ(VecCopy(mglevels->b, mglevels->crb)); */ 116 CHKERRQ(KSPSetNoisy_Private(mglevels->crx)); 117 CHKERRQ(KSPSolve(mglevels->cr,mglevels->crb,mglevels->crx)); /* compatible relaxation */ 118 CHKERRQ(KSPCheckSolve(mglevels->cr,pc,mglevels->crx)); 119 } 120 if (mglevels->eventsmoothsolve) CHKERRQ(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 CHKERRQ(KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL)); 138 CHKERRQ(PetscObjectReference((PetscObject)mglevels[i]->A)); 139 } 140 } 141 142 CHKERRQ(KSPGetPC(mglevels[levels-1]->smoothd,&tpc)); 143 CHKERRQ(PCPreSolveChangeRHS(tpc,&changed)); 144 CHKERRQ(KSPGetPC(mglevels[levels-1]->smoothu,&tpc)); 145 CHKERRQ(PCPreSolveChangeRHS(tpc,&changeu)); 146 if (!changed && !changeu) { 147 CHKERRQ(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 CHKERRQ(KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL)); 154 mglevels[levels-1]->b = *vec; 155 CHKERRQ(PetscFree(vec)); 156 } 157 CHKERRQ(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 CHKERRQ(VecNorm(b,NORM_2,&rnorm)); 169 } else { 170 CHKERRQ((*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w)); 171 CHKERRQ(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 CHKERRQ(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 CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE)); 184 CHKERRQ(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 CHKERRQ(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 CHKERRQ(VecDestroy(&mglevels[i+1]->r)); 210 CHKERRQ(VecDestroy(&mglevels[i]->b)); 211 CHKERRQ(VecDestroy(&mglevels[i]->x)); 212 CHKERRQ(MatDestroy(&mglevels[i+1]->R)); 213 CHKERRQ(MatDestroy(&mglevels[i]->B)); 214 CHKERRQ(MatDestroy(&mglevels[i]->X)); 215 CHKERRQ(VecDestroy(&mglevels[i]->crx)); 216 CHKERRQ(VecDestroy(&mglevels[i]->crb)); 217 CHKERRQ(MatDestroy(&mglevels[i+1]->restrct)); 218 CHKERRQ(MatDestroy(&mglevels[i+1]->interpolate)); 219 CHKERRQ(MatDestroy(&mglevels[i+1]->inject)); 220 CHKERRQ(VecDestroy(&mglevels[i+1]->rscale)); 221 } 222 CHKERRQ(VecDestroy(&mglevels[n-1]->crx)); 223 CHKERRQ(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 CHKERRQ(VecDestroy(&mglevels[n-1]->b)); 227 CHKERRQ(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) CHKERRQ(VecDestroy(&mglevels[i]->coarseSpace[c])); 231 CHKERRQ(PetscFree(mglevels[i]->coarseSpace)); 232 mglevels[i]->coarseSpace = NULL; 233 CHKERRQ(MatDestroy(&mglevels[i]->A)); 234 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 235 CHKERRQ(KSPReset(mglevels[i]->smoothd)); 236 } 237 CHKERRQ(KSPReset(mglevels[i]->smoothu)); 238 if (mglevels[i]->cr) CHKERRQ(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 CHKERRQ(PCShellGetContext(pc, &ctx)); 291 CHKERRQ(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 CHKERRQ(MatCreateTranspose(It, &ctx->Inj)); 294 CHKERRQ(MatCreateNormal(ctx->Inj, &ctx->S)); 295 CHKERRQ(MatScale(ctx->S, -1.0)); 296 CHKERRQ(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 CHKERRQ(PCShellGetContext(pc, &ctx)); 306 CHKERRQ(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 CHKERRQ(PCShellGetContext(pc, &ctx)); 316 CHKERRQ(MatDestroy(&ctx->Inj)); 317 CHKERRQ(MatDestroy(&ctx->S)); 318 CHKERRQ(PetscFree(ctx)); 319 CHKERRQ(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 CHKERRQ(PCCreate(PetscObjectComm((PetscObject) pc), cr)); 329 CHKERRQ(PetscObjectSetName((PetscObject) *cr, "S (complementary projector to injection)")); 330 CHKERRQ(PetscCalloc1(1, &ctx)); 331 ctx->mg = pc; 332 ctx->l = l; 333 CHKERRQ(PCSetType(*cr, PCSHELL)); 334 CHKERRQ(PCShellSetContext(*cr, ctx)); 335 CHKERRQ(PCShellSetApply(*cr, CRApply_Private)); 336 CHKERRQ(PCShellSetSetUp(*cr, CRSetup_Private)); 337 CHKERRQ(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 CHKERRQ(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 CHKERRQ(PCReset_MG(pc)); 363 n = mglevels[0]->levels; 364 for (i=0; i<n; i++) { 365 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 366 CHKERRQ(KSPDestroy(&mglevels[i]->smoothd)); 367 } 368 CHKERRQ(KSPDestroy(&mglevels[i]->smoothu)); 369 CHKERRQ(KSPDestroy(&mglevels[i]->cr)); 370 CHKERRQ(PetscFree(mglevels[i])); 371 } 372 CHKERRQ(PetscFree(mg->levels)); 373 } 374 375 mg->nlevels = levels; 376 377 CHKERRQ(PetscMalloc1(levels,&mglevels)); 378 CHKERRQ(PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)))); 379 380 CHKERRQ(PCGetOptionsPrefix(pc,&prefix)); 381 382 mg->stageApply = 0; 383 for (i=0; i<levels; i++) { 384 CHKERRQ(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 CHKERRQ(KSPCreate(comm,&mglevels[i]->smoothd)); 399 CHKERRQ(KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure)); 400 CHKERRQ(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i)); 401 CHKERRQ(KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix)); 402 CHKERRQ(PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level)); 403 if (i || levels == 1) { 404 char tprefix[128]; 405 406 CHKERRQ(KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV)); 407 CHKERRQ(KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL)); 408 CHKERRQ(KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE)); 409 CHKERRQ(KSPGetPC(mglevels[i]->smoothd,&ipc)); 410 CHKERRQ(PCSetType(ipc,PCSOR)); 411 CHKERRQ(KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd)); 412 413 CHKERRQ(PetscSNPrintf(tprefix,128,"mg_levels_%d_",(int)i)); 414 CHKERRQ(KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix)); 415 } else { 416 CHKERRQ(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 CHKERRQ(KSPSetType(mglevels[0]->smoothd,KSPPREONLY)); 420 CHKERRQ(KSPGetPC(mglevels[0]->smoothd,&ipc)); 421 CHKERRMPI(MPI_Comm_size(comm,&size)); 422 if (size > 1) { 423 CHKERRQ(PCSetType(ipc,PCREDUNDANT)); 424 } else { 425 CHKERRQ(PCSetType(ipc,PCLU)); 426 } 427 CHKERRQ(PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS)); 428 } 429 CHKERRQ(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 CHKERRQ(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 CHKERRQ(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 CHKERRQ(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 CHKERRQ(KSPDestroy(&mglevels[i]->smoothd)); 508 } 509 CHKERRQ(KSPDestroy(&mglevels[i]->smoothu)); 510 CHKERRQ(KSPDestroy(&mglevels[i]->cr)); 511 CHKERRQ(PetscFree(mglevels[i])); 512 } 513 CHKERRQ(PetscFree(mg->levels)); 514 } 515 CHKERRQ(PetscFree(pc->data)); 516 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",NULL)); 517 CHKERRQ(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) CHKERRQ(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 CHKERRQ(KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL)); 543 CHKERRQ(PetscObjectReference((PetscObject)mglevels[i]->A)); 544 } 545 } 546 547 CHKERRQ(KSPGetPC(mglevels[levels-1]->smoothd,&tpc)); 548 CHKERRQ(PCPreSolveChangeRHS(tpc,&changed)); 549 CHKERRQ(KSPGetPC(mglevels[levels-1]->smoothu,&tpc)); 550 CHKERRQ(PCPreSolveChangeRHS(tpc,&changeu)); 551 if (!changeu && !changed) { 552 if (matapp) { 553 CHKERRQ(MatDestroy(&mglevels[levels-1]->B)); 554 mglevels[levels-1]->B = B; 555 } else { 556 CHKERRQ(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 CHKERRQ(MatGetSize(mglevels[levels-1]->B,NULL,&N1)); 566 CHKERRQ(MatGetSize(B,NULL,&N2)); 567 CHKERRQ(PetscObjectTypeCompare((PetscObject)mglevels[levels-1]->B,((PetscObject)B)->type_name,&flg)); 568 if (N1 != N2 || !flg) { 569 CHKERRQ(MatDestroy(&mglevels[levels-1]->B)); 570 } 571 } 572 if (!mglevels[levels-1]->B) { 573 CHKERRQ(MatDuplicate(B,MAT_COPY_VALUES,&mglevels[levels-1]->B)); 574 } else { 575 CHKERRQ(MatCopy(B,mglevels[levels-1]->B,SAME_NONZERO_PATTERN)); 576 } 577 } else { 578 if (!mglevels[levels-1]->b) { 579 Vec *vec; 580 581 CHKERRQ(KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL)); 582 mglevels[levels-1]->b = *vec; 583 CHKERRQ(PetscFree(vec)); 584 } 585 CHKERRQ(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 CHKERRQ(MatGetSize(mglevels[levels-2]->X,NULL,&Xc)); 598 CHKERRQ(MatGetSize(mglevels[levels-1]->B,NULL,&Bc)); 599 CHKERRQ(PetscObjectTypeCompare((PetscObject)mglevels[levels-2]->X,((PetscObject)mglevels[levels-1]->X)->type_name,&flg)); 600 if (Xc != Bc || !flg) { 601 CHKERRQ(MatDestroy(&mglevels[levels-1]->R)); 602 for (i=0;i<levels-1;i++) { 603 CHKERRQ(MatDestroy(&mglevels[i]->R)); 604 CHKERRQ(MatDestroy(&mglevels[i]->B)); 605 CHKERRQ(MatDestroy(&mglevels[i]->X)); 606 } 607 } 608 } 609 610 if (mg->am == PC_MG_MULTIPLICATIVE) { 611 if (matapp) CHKERRQ(MatZeroEntries(X)); 612 else CHKERRQ(VecZeroEntries(x)); 613 for (i=0; i<mg->cyclesperpcapply; i++) { 614 CHKERRQ(PCMGMCycle_Private(pc,mglevels+levels-1,transpose,matapp,NULL)); 615 } 616 } else if (mg->am == PC_MG_ADDITIVE) { 617 CHKERRQ(PCMGACycle_Private(pc,mglevels,transpose,matapp)); 618 } else if (mg->am == PC_MG_KASKADE) { 619 CHKERRQ(PCMGKCycle_Private(pc,mglevels,transpose,matapp)); 620 } else { 621 CHKERRQ(PCMGFCycle_Private(pc,mglevels,transpose,matapp)); 622 } 623 if (mg->stageApply) CHKERRQ(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 CHKERRQ(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 CHKERRQ(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 CHKERRQ(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 CHKERRQ(PetscOptionsHead(PetscOptionsObject,"Multigrid options")); 665 CHKERRQ(PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg)); 666 if (!flg && !mg->levels && pc->dm) { 667 CHKERRQ(DMGetRefineLevel(pc->dm,&levels)); 668 levels++; 669 mg->usedmfornumberoflevels = PETSC_TRUE; 670 } 671 CHKERRQ(PCMGSetLevels(pc,levels,NULL)); 672 mglevels = mg->levels; 673 674 mgctype = (PCMGCycleType) mglevels[0]->cycles; 675 CHKERRQ(PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg)); 676 if (flg) { 677 CHKERRQ(PCMGSetCycleType(pc,mgctype)); 678 } 679 gtype = mg->galerkin; 680 CHKERRQ(PetscOptionsEnum("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",PCMGGalerkinTypes,(PetscEnum)gtype,(PetscEnum*)>ype,&flg)); 681 if (flg) { 682 CHKERRQ(PCMGSetGalerkin(pc,gtype)); 683 } 684 flg2 = PETSC_FALSE; 685 CHKERRQ(PetscOptionsBool("-pc_mg_adapt_interp","Adapt interpolation using some coarse space","PCMGSetAdaptInterpolation",PETSC_FALSE,&flg2,&flg)); 686 if (flg) CHKERRQ(PCMGSetAdaptInterpolation(pc, flg2)); 687 CHKERRQ(PetscOptionsInt("-pc_mg_adapt_interp_n","Size of the coarse space for adaptive interpolation","PCMGSetCoarseSpace",mg->Nc,&mg->Nc,&flg)); 688 CHKERRQ(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 CHKERRQ(PetscOptionsBool("-pc_mg_mesp_monitor","Monitor the multilevel eigensolver","PCMGSetAdaptInterpolation",PETSC_FALSE,&mg->mespMonitor,&flg)); 690 flg2 = PETSC_FALSE; 691 CHKERRQ(PetscOptionsBool("-pc_mg_adapt_cr","Monitor coarse space quality using Compatible Relaxation (CR)","PCMGSetAdaptCR",PETSC_FALSE,&flg2,&flg)); 692 if (flg) CHKERRQ(PCMGSetAdaptCR(pc, flg2)); 693 flg = PETSC_FALSE; 694 CHKERRQ(PetscOptionsBool("-pc_mg_distinct_smoothup","Create separate smoothup KSP and append the prefix _up","PCMGSetDistinctSmoothUp",PETSC_FALSE,&flg,NULL)); 695 if (flg) { 696 CHKERRQ(PCMGSetDistinctSmoothUp(pc)); 697 } 698 mgtype = mg->am; 699 CHKERRQ(PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg)); 700 if (flg) { 701 CHKERRQ(PCMGSetType(pc,mgtype)); 702 } 703 if (mg->am == PC_MG_MULTIPLICATIVE) { 704 CHKERRQ(PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGMultiplicativeSetCycles",mg->cyclesperpcapply,&cycles,&flg)); 705 if (flg) { 706 CHKERRQ(PCMGMultiplicativeSetCycles(pc,cycles)); 707 } 708 } 709 flg = PETSC_FALSE; 710 CHKERRQ(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 CHKERRQ(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup)); 719 sprintf(eventname,"MGSmooth Level %d",(int)i); 720 CHKERRQ(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve)); 721 if (i) { 722 sprintf(eventname,"MGResid Level %d",(int)i); 723 CHKERRQ(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual)); 724 sprintf(eventname,"MGInterp Level %d",(int)i); 725 CHKERRQ(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 CHKERRQ(PetscLogGetStageLog(&stageLog)); 736 for (st = 0; st < stageLog->numStages; ++st) { 737 PetscBool same; 738 739 CHKERRQ(PetscStrcmp(stageLog->stageInfo[st].name, sname, &same)); 740 if (same) mg->stageApply = st; 741 } 742 if (!mg->stageApply) { 743 CHKERRQ(PetscLogStageRegister(sname, &mg->stageApply)); 744 } 745 } 746 #endif 747 } 748 CHKERRQ(PetscOptionsTail()); 749 /* Check option consistency */ 750 CHKERRQ(PCMGGetGalerkin(pc, >ype)); 751 CHKERRQ(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 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 771 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary)); 772 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw)); 773 if (iascii) { 774 const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 775 CHKERRQ(PetscViewerASCIIPrintf(viewer," type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename)); 776 if (mg->am == PC_MG_MULTIPLICATIVE) { 777 CHKERRQ(PetscViewerASCIIPrintf(viewer," Cycles per PCApply=%d\n",mg->cyclesperpcapply)); 778 } 779 if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 780 CHKERRQ(PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n")); 781 } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 782 CHKERRQ(PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices for pmat\n")); 783 } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 784 CHKERRQ(PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices for mat\n")); 785 } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 786 CHKERRQ(PetscViewerASCIIPrintf(viewer," Using externally compute Galerkin coarse grid matrices\n")); 787 } else { 788 CHKERRQ(PetscViewerASCIIPrintf(viewer," Not using Galerkin computed coarse grid matrices\n")); 789 } 790 if (mg->view) { 791 CHKERRQ((*mg->view)(pc,viewer)); 792 } 793 for (i=0; i<levels; i++) { 794 if (!i) { 795 CHKERRQ(PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i)); 796 } else { 797 CHKERRQ(PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i)); 798 } 799 CHKERRQ(PetscViewerASCIIPushTab(viewer)); 800 CHKERRQ(KSPView(mglevels[i]->smoothd,viewer)); 801 CHKERRQ(PetscViewerASCIIPopTab(viewer)); 802 if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 803 CHKERRQ(PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n")); 804 } else if (i) { 805 CHKERRQ(PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i)); 806 CHKERRQ(PetscViewerASCIIPushTab(viewer)); 807 CHKERRQ(KSPView(mglevels[i]->smoothu,viewer)); 808 CHKERRQ(PetscViewerASCIIPopTab(viewer)); 809 } 810 if (i && mglevels[i]->cr) { 811 CHKERRQ(PetscViewerASCIIPrintf(viewer,"CR solver on level %D -------------------------------\n",i)); 812 CHKERRQ(PetscViewerASCIIPushTab(viewer)); 813 CHKERRQ(KSPView(mglevels[i]->cr,viewer)); 814 CHKERRQ(PetscViewerASCIIPopTab(viewer)); 815 } 816 } 817 } else if (isbinary) { 818 for (i=levels-1; i>=0; i--) { 819 CHKERRQ(KSPView(mglevels[i]->smoothd,viewer)); 820 if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) { 821 CHKERRQ(KSPView(mglevels[i]->smoothu,viewer)); 822 } 823 } 824 } else if (isdraw) { 825 PetscDraw draw; 826 PetscReal x,w,y,bottom,th; 827 CHKERRQ(PetscViewerDrawGetDraw(viewer,0,&draw)); 828 CHKERRQ(PetscDrawGetCurrentPoint(draw,&x,&y)); 829 CHKERRQ(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 CHKERRQ(PetscDrawPushCurrentPoint(draw,x,bottom)); 834 CHKERRQ(KSPView(mglevels[i]->smoothd,viewer)); 835 CHKERRQ(PetscDrawPopCurrentPoint(draw)); 836 } else { 837 w = 0.5*PetscMin(1.0-x,x); 838 CHKERRQ(PetscDrawPushCurrentPoint(draw,x+w,bottom)); 839 CHKERRQ(KSPView(mglevels[i]->smoothd,viewer)); 840 CHKERRQ(PetscDrawPopCurrentPoint(draw)); 841 CHKERRQ(PetscDrawPushCurrentPoint(draw,x-w,bottom)); 842 CHKERRQ(KSPView(mglevels[i]->smoothu,viewer)); 843 CHKERRQ(PetscDrawPopCurrentPoint(draw)); 844 } 845 CHKERRQ(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 CHKERRQ(DMGetRefineLevel(pc->dm,&levels)); 877 levels++; 878 if (levels > n) { /* the problem is now being solved on a finer grid */ 879 CHKERRQ(PCMGSetLevels(pc,levels,NULL)); 880 n = levels; 881 CHKERRQ(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 CHKERRQ(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 CHKERRQ(KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset)); 891 if (opsset) { 892 Mat mmat; 893 CHKERRQ(KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat)); 894 if (mmat == pc->pmat) opsset = PETSC_FALSE; 895 } 896 897 /* Create CR solvers */ 898 CHKERRQ(PCMGGetAdaptCR(pc, &doCR)); 899 if (doCR) { 900 const char *prefix; 901 902 CHKERRQ(PCGetOptionsPrefix(pc, &prefix)); 903 for (i = 1; i < n; ++i) { 904 PC ipc, cr; 905 char crprefix[128]; 906 907 CHKERRQ(KSPCreate(PetscObjectComm((PetscObject) pc), &mglevels[i]->cr)); 908 CHKERRQ(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE)); 909 CHKERRQ(PetscObjectIncrementTabLevel((PetscObject) mglevels[i]->cr, (PetscObject) pc, n-i)); 910 CHKERRQ(KSPSetOptionsPrefix(mglevels[i]->cr, prefix)); 911 CHKERRQ(PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level)); 912 CHKERRQ(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV)); 913 CHKERRQ(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL)); 914 CHKERRQ(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED)); 915 CHKERRQ(KSPGetPC(mglevels[i]->cr, &ipc)); 916 917 CHKERRQ(PCSetType(ipc, PCCOMPOSITE)); 918 CHKERRQ(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE)); 919 CHKERRQ(PCCompositeAddPCType(ipc, PCSOR)); 920 CHKERRQ(CreateCR_Private(pc, i, &cr)); 921 CHKERRQ(PCCompositeAddPC(ipc, cr)); 922 CHKERRQ(PCDestroy(&cr)); 923 924 CHKERRQ(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd)); 925 CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE)); 926 CHKERRQ(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int) i)); 927 CHKERRQ(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix)); 928 CHKERRQ(PetscLogObjectParent((PetscObject) pc, (PetscObject) mglevels[i]->cr)); 929 } 930 } 931 932 if (!opsset) { 933 CHKERRQ(PCGetUseAmat(pc,&use_amat)); 934 if (use_amat) { 935 CHKERRQ(PetscInfo(pc,"Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n")); 936 CHKERRQ(KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat)); 937 } else { 938 CHKERRQ(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 CHKERRQ(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 CHKERRQ(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 CHKERRQ(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--) CHKERRQ(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 CHKERRQ(DMSetMatType(dms[0],MATAIJ)); 975 */ 976 for (i=n-2; i>-1; i--) { 977 DMKSP kdm; 978 PetscBool dmhasrestrict, dmhasinject; 979 CHKERRQ(KSPSetDM(mglevels[i]->smoothd,dms[i])); 980 if (!needRestricts) CHKERRQ(KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE)); 981 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 982 CHKERRQ(KSPSetDM(mglevels[i]->smoothu,dms[i])); 983 if (!needRestricts) CHKERRQ(KSPSetDMActive(mglevels[i]->smoothu,PETSC_FALSE)); 984 } 985 if (mglevels[i]->cr) { 986 CHKERRQ(KSPSetDM(mglevels[i]->cr,dms[i])); 987 if (!needRestricts) CHKERRQ(KSPSetDMActive(mglevels[i]->cr,PETSC_FALSE)); 988 } 989 CHKERRQ(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 CHKERRQ(DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale)); 996 CHKERRQ(PCMGSetInterpolation(pc,i+1,p)); 997 if (rscale) CHKERRQ(PCMGSetRScale(pc,i+1,rscale)); 998 CHKERRQ(VecDestroy(&rscale)); 999 CHKERRQ(MatDestroy(&p)); 1000 } 1001 CHKERRQ(DMHasCreateRestriction(dms[i],&dmhasrestrict)); 1002 if (dmhasrestrict && !mglevels[i+1]->restrct) { 1003 CHKERRQ(DMCreateRestriction(dms[i],dms[i+1],&p)); 1004 CHKERRQ(PCMGSetRestriction(pc,i+1,p)); 1005 CHKERRQ(MatDestroy(&p)); 1006 } 1007 CHKERRQ(DMHasCreateInjection(dms[i],&dmhasinject)); 1008 if (dmhasinject && !mglevels[i+1]->inject) { 1009 CHKERRQ(DMCreateInjection(dms[i],dms[i+1],&p)); 1010 CHKERRQ(PCMGSetInjection(pc,i+1,p)); 1011 CHKERRQ(MatDestroy(&p)); 1012 } 1013 } 1014 1015 for (i=n-2; i>-1; i--) CHKERRQ(DMDestroy(&dms[i])); 1016 CHKERRQ(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 CHKERRQ(KSPSetDM(mglevels[n-1]->smoothd,pc->dm)); 1022 CHKERRQ(KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE)); 1023 if (mglevels[n-1]->smoothd != mglevels[n-1]->smoothu) { 1024 CHKERRQ(KSPSetDM(mglevels[n-1]->smoothu,pc->dm)); 1025 CHKERRQ(KSPSetDMActive(mglevels[n-1]->smoothu,PETSC_FALSE)); 1026 } 1027 if (mglevels[n-1]->cr) { 1028 CHKERRQ(KSPSetDM(mglevels[n-1]->cr,pc->dm)); 1029 CHKERRQ(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 PetscCheckFalse(!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 CHKERRQ(PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct)); 1045 } 1046 if (!mglevels[i+1]->restrct) { 1047 CHKERRQ(PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate)); 1048 } 1049 if (reuse == MAT_REUSE_MATRIX) { 1050 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&A,&B)); 1051 } 1052 if (doA) { 1053 CHKERRQ(MatGalerkin(mglevels[i+1]->restrct,dA,mglevels[i+1]->interpolate,reuse,1.0,&A)); 1054 } 1055 if (doB) { 1056 CHKERRQ(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) CHKERRQ(PetscObjectReference((PetscObject)B)); 1061 A = B; 1062 } else if (!doA && reuse == MAT_INITIAL_MATRIX) { 1063 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&A,NULL)); 1064 CHKERRQ(PetscObjectReference((PetscObject)A)); 1065 } 1066 if (!doB && dAeqdB) { 1067 if (reuse == MAT_INITIAL_MATRIX) CHKERRQ(PetscObjectReference((PetscObject)A)); 1068 B = A; 1069 } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 1070 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,NULL,&B)); 1071 CHKERRQ(PetscObjectReference((PetscObject)B)); 1072 } 1073 if (reuse == MAT_INITIAL_MATRIX) { 1074 CHKERRQ(KSPSetOperators(mglevels[i]->smoothd,A,B)); 1075 CHKERRQ(PetscObjectDereference((PetscObject)A)); 1076 CHKERRQ(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 CHKERRQ(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i-1]->coarseSpace, &mglevels[i]->coarseSpace)); 1088 if (i) CHKERRQ(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 CHKERRQ(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 CHKERRQ(KSPGetDM(mglevels[i+1]->smoothd,&dmfine)); 1101 CHKERRQ(KSPGetDM(mglevels[i]->smoothd,&dmcoarse)); 1102 CHKERRQ(PCMGGetRestriction(pc,i+1,&Restrict)); 1103 CHKERRQ(PCMGGetRScale(pc,i+1,&rscale)); 1104 CHKERRQ(PCMGGetInjection(pc,i+1,&Inject)); 1105 CHKERRQ(DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse)); 1106 } 1107 } 1108 1109 if (!pc->setupcalled) { 1110 for (i=0; i<n; i++) { 1111 CHKERRQ(KSPSetFromOptions(mglevels[i]->smoothd)); 1112 } 1113 for (i=1; i<n; i++) { 1114 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 1115 CHKERRQ(KSPSetFromOptions(mglevels[i]->smoothu)); 1116 } 1117 if (mglevels[i]->cr) { 1118 CHKERRQ(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 CHKERRQ(PCMGGetInterpolation(pc,i,NULL)); 1124 CHKERRQ(PCMGGetRestriction(pc,i,NULL)); 1125 } 1126 for (i=0; i<n-1; i++) { 1127 if (!mglevels[i]->b) { 1128 Vec *vec; 1129 CHKERRQ(KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL)); 1130 CHKERRQ(PCMGSetRhs(pc,i,*vec)); 1131 CHKERRQ(VecDestroy(vec)); 1132 CHKERRQ(PetscFree(vec)); 1133 } 1134 if (!mglevels[i]->r && i) { 1135 CHKERRQ(VecDuplicate(mglevels[i]->b,&tvec)); 1136 CHKERRQ(PCMGSetR(pc,i,tvec)); 1137 CHKERRQ(VecDestroy(&tvec)); 1138 } 1139 if (!mglevels[i]->x) { 1140 CHKERRQ(VecDuplicate(mglevels[i]->b,&tvec)); 1141 CHKERRQ(PCMGSetX(pc,i,tvec)); 1142 CHKERRQ(VecDestroy(&tvec)); 1143 } 1144 if (doCR) { 1145 CHKERRQ(VecDuplicate(mglevels[i]->b,&mglevels[i]->crx)); 1146 CHKERRQ(VecDuplicate(mglevels[i]->b,&mglevels[i]->crb)); 1147 CHKERRQ(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 CHKERRQ(KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL)); 1154 CHKERRQ(PCMGSetR(pc,n-1,*vec)); 1155 CHKERRQ(VecDestroy(vec)); 1156 CHKERRQ(PetscFree(vec)); 1157 } 1158 if (doCR) { 1159 CHKERRQ(VecDuplicate(mglevels[n-1]->r, &mglevels[n-1]->crx)); 1160 CHKERRQ(VecDuplicate(mglevels[n-1]->r, &mglevels[n-1]->crb)); 1161 CHKERRQ(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 1172 for (i=1; i<n; i++) { 1173 if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) { 1174 /* if doing only down then initial guess is zero */ 1175 CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE)); 1176 } 1177 if (mglevels[i]->cr) CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->cr,PETSC_TRUE)); 1178 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1179 CHKERRQ(KSPSetUp(mglevels[i]->smoothd)); 1180 if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { 1181 pc->failedreason = PC_SUBPC_ERROR; 1182 } 1183 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1184 if (!mglevels[i]->residual) { 1185 Mat mat; 1186 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&mat,NULL)); 1187 CHKERRQ(PCMGSetResidual(pc,i,PCMGResidualDefault,mat)); 1188 } 1189 if (!mglevels[i]->residualtranspose) { 1190 Mat mat; 1191 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&mat,NULL)); 1192 CHKERRQ(PCMGSetResidualTranspose(pc,i,PCMGResidualTransposeDefault,mat)); 1193 } 1194 } 1195 for (i=1; i<n; i++) { 1196 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 1197 Mat downmat,downpmat; 1198 1199 /* check if operators have been set for up, if not use down operators to set them */ 1200 CHKERRQ(KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL)); 1201 if (!opsset) { 1202 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat)); 1203 CHKERRQ(KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat)); 1204 } 1205 1206 CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE)); 1207 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1208 CHKERRQ(KSPSetUp(mglevels[i]->smoothu)); 1209 if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) { 1210 pc->failedreason = PC_SUBPC_ERROR; 1211 } 1212 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1213 } 1214 if (mglevels[i]->cr) { 1215 Mat downmat,downpmat; 1216 1217 /* check if operators have been set for up, if not use down operators to set them */ 1218 CHKERRQ(KSPGetOperatorsSet(mglevels[i]->cr,&opsset,NULL)); 1219 if (!opsset) { 1220 CHKERRQ(KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat)); 1221 CHKERRQ(KSPSetOperators(mglevels[i]->cr,downmat,downpmat)); 1222 } 1223 1224 CHKERRQ(KSPSetInitialGuessNonzero(mglevels[i]->cr,PETSC_TRUE)); 1225 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1226 CHKERRQ(KSPSetUp(mglevels[i]->cr)); 1227 if (mglevels[i]->cr->reason == KSP_DIVERGED_PC_FAILED) { 1228 pc->failedreason = PC_SUBPC_ERROR; 1229 } 1230 if (mglevels[i]->eventsmoothsetup) CHKERRQ(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0)); 1231 } 1232 } 1233 1234 if (mglevels[0]->eventsmoothsetup) CHKERRQ(PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0)); 1235 CHKERRQ(KSPSetUp(mglevels[0]->smoothd)); 1236 if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { 1237 pc->failedreason = PC_SUBPC_ERROR; 1238 } 1239 if (mglevels[0]->eventsmoothsetup) CHKERRQ(PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0)); 1240 1241 /* 1242 Dump the interpolation/restriction matrices plus the 1243 Jacobian/stiffness on each level. This allows MATLAB users to 1244 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 1245 1246 Only support one or the other at the same time. 1247 */ 1248 #if defined(PETSC_USE_SOCKET_VIEWER) 1249 CHKERRQ(PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL)); 1250 if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 1251 dump = PETSC_FALSE; 1252 #endif 1253 CHKERRQ(PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL)); 1254 if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 1255 1256 if (viewer) { 1257 for (i=1; i<n; i++) { 1258 CHKERRQ(MatView(mglevels[i]->restrct,viewer)); 1259 } 1260 for (i=0; i<n; i++) { 1261 CHKERRQ(KSPGetPC(mglevels[i]->smoothd,&pc)); 1262 CHKERRQ(MatView(pc->mat,viewer)); 1263 } 1264 } 1265 PetscFunctionReturn(0); 1266 } 1267 1268 /* -------------------------------------------------------------------------------------*/ 1269 1270 PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 1271 { 1272 PC_MG *mg = (PC_MG *) pc->data; 1273 1274 PetscFunctionBegin; 1275 *levels = mg->nlevels; 1276 PetscFunctionReturn(0); 1277 } 1278 1279 /*@ 1280 PCMGGetLevels - Gets the number of levels to use with MG. 1281 1282 Not Collective 1283 1284 Input Parameter: 1285 . pc - the preconditioner context 1286 1287 Output parameter: 1288 . levels - the number of levels 1289 1290 Level: advanced 1291 1292 .seealso: PCMGSetLevels() 1293 @*/ 1294 PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels) 1295 { 1296 PetscFunctionBegin; 1297 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1298 PetscValidIntPointer(levels,2); 1299 *levels = 0; 1300 CHKERRQ(PetscTryMethod(pc,"PCMGGetLevels_C",(PC,PetscInt*),(pc,levels))); 1301 PetscFunctionReturn(0); 1302 } 1303 1304 /*@ 1305 PCMGGetGridComplexity - compute operator and grid complexity of MG hierarchy 1306 1307 Input Parameter: 1308 . pc - the preconditioner context 1309 1310 Output Parameters: 1311 + gc - grid complexity = sum_i(n_i) / n_0 1312 - oc - operator complexity = sum_i(nnz_i) / nnz_0 1313 1314 Level: advanced 1315 1316 .seealso: PCMGGetLevels() 1317 @*/ 1318 PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) 1319 { 1320 PC_MG *mg = (PC_MG*)pc->data; 1321 PC_MG_Levels **mglevels = mg->levels; 1322 PetscInt lev,N; 1323 PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0; 1324 MatInfo info; 1325 1326 PetscFunctionBegin; 1327 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1328 if (gc) PetscValidRealPointer(gc,2); 1329 if (oc) PetscValidRealPointer(oc,3); 1330 if (!pc->setupcalled) { 1331 if (gc) *gc = 0; 1332 if (oc) *oc = 0; 1333 PetscFunctionReturn(0); 1334 } 1335 PetscCheck(mg->nlevels > 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"MG has no levels"); 1336 for (lev=0; lev<mg->nlevels; lev++) { 1337 Mat dB; 1338 CHKERRQ(KSPGetOperators(mglevels[lev]->smoothd,NULL,&dB)); 1339 CHKERRQ(MatGetInfo(dB,MAT_GLOBAL_SUM,&info)); /* global reduction */ 1340 CHKERRQ(MatGetSize(dB,&N,NULL)); 1341 sgc += N; 1342 soc += info.nz_used; 1343 if (lev==mg->nlevels-1) {nnz0 = info.nz_used; n0 = N;} 1344 } 1345 if (n0 > 0 && gc) *gc = (PetscReal)(sgc/n0); 1346 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number for grid points on finest level is not available"); 1347 if (nnz0 > 0 && oc) *oc = (PetscReal)(soc/nnz0); 1348 PetscFunctionReturn(0); 1349 } 1350 1351 /*@ 1352 PCMGSetType - Determines the form of multigrid to use: 1353 multiplicative, additive, full, or the Kaskade algorithm. 1354 1355 Logically Collective on PC 1356 1357 Input Parameters: 1358 + pc - the preconditioner context 1359 - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 1360 PC_MG_FULL, PC_MG_KASKADE 1361 1362 Options Database Key: 1363 . -pc_mg_type <form> - Sets <form>, one of multiplicative, 1364 additive, full, kaskade 1365 1366 Level: advanced 1367 1368 .seealso: PCMGSetLevels() 1369 @*/ 1370 PetscErrorCode PCMGSetType(PC pc,PCMGType form) 1371 { 1372 PC_MG *mg = (PC_MG*)pc->data; 1373 1374 PetscFunctionBegin; 1375 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1376 PetscValidLogicalCollectiveEnum(pc,form,2); 1377 mg->am = form; 1378 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 1379 else pc->ops->applyrichardson = NULL; 1380 PetscFunctionReturn(0); 1381 } 1382 1383 /*@ 1384 PCMGGetType - Determines the form of multigrid to use: 1385 multiplicative, additive, full, or the Kaskade algorithm. 1386 1387 Logically Collective on PC 1388 1389 Input Parameter: 1390 . pc - the preconditioner context 1391 1392 Output Parameter: 1393 . type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE 1394 1395 Level: advanced 1396 1397 .seealso: PCMGSetLevels() 1398 @*/ 1399 PetscErrorCode PCMGGetType(PC pc,PCMGType *type) 1400 { 1401 PC_MG *mg = (PC_MG*)pc->data; 1402 1403 PetscFunctionBegin; 1404 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1405 *type = mg->am; 1406 PetscFunctionReturn(0); 1407 } 1408 1409 /*@ 1410 PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 1411 complicated cycling. 1412 1413 Logically Collective on PC 1414 1415 Input Parameters: 1416 + pc - the multigrid context 1417 - n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W 1418 1419 Options Database Key: 1420 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1421 1422 Level: advanced 1423 1424 .seealso: PCMGSetCycleTypeOnLevel() 1425 @*/ 1426 PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n) 1427 { 1428 PC_MG *mg = (PC_MG*)pc->data; 1429 PC_MG_Levels **mglevels = mg->levels; 1430 PetscInt i,levels; 1431 1432 PetscFunctionBegin; 1433 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1434 PetscValidLogicalCollectiveEnum(pc,n,2); 1435 PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1436 levels = mglevels[0]->levels; 1437 for (i=0; i<levels; i++) mglevels[i]->cycles = n; 1438 PetscFunctionReturn(0); 1439 } 1440 1441 /*@ 1442 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1443 of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 1444 1445 Logically Collective on PC 1446 1447 Input Parameters: 1448 + pc - the multigrid context 1449 - n - number of cycles (default is 1) 1450 1451 Options Database Key: 1452 . -pc_mg_multiplicative_cycles n - set the number of cycles 1453 1454 Level: advanced 1455 1456 Notes: 1457 This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 1458 1459 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType() 1460 @*/ 1461 PetscErrorCode PCMGMultiplicativeSetCycles(PC pc,PetscInt n) 1462 { 1463 PC_MG *mg = (PC_MG*)pc->data; 1464 1465 PetscFunctionBegin; 1466 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1467 PetscValidLogicalCollectiveInt(pc,n,2); 1468 mg->cyclesperpcapply = n; 1469 PetscFunctionReturn(0); 1470 } 1471 1472 PetscErrorCode PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use) 1473 { 1474 PC_MG *mg = (PC_MG*)pc->data; 1475 1476 PetscFunctionBegin; 1477 mg->galerkin = use; 1478 PetscFunctionReturn(0); 1479 } 1480 1481 /*@ 1482 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 1483 finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1484 1485 Logically Collective on PC 1486 1487 Input Parameters: 1488 + pc - the multigrid context 1489 - use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE 1490 1491 Options Database Key: 1492 . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process 1493 1494 Level: intermediate 1495 1496 Notes: 1497 Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not 1498 use the PCMG construction of the coarser grids. 1499 1500 .seealso: PCMGGetGalerkin(), PCMGGalerkinType 1501 1502 @*/ 1503 PetscErrorCode PCMGSetGalerkin(PC pc,PCMGGalerkinType use) 1504 { 1505 PetscFunctionBegin; 1506 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1507 CHKERRQ(PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PCMGGalerkinType),(pc,use))); 1508 PetscFunctionReturn(0); 1509 } 1510 1511 /*@ 1512 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 1513 A_i-1 = r_i * A_i * p_i 1514 1515 Not Collective 1516 1517 Input Parameter: 1518 . pc - the multigrid context 1519 1520 Output Parameter: 1521 . galerkin - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, PC_MG_GALERKIN_NONE, or PC_MG_GALERKIN_EXTERNAL 1522 1523 Level: intermediate 1524 1525 .seealso: PCMGSetGalerkin(), PCMGGalerkinType 1526 1527 @*/ 1528 PetscErrorCode PCMGGetGalerkin(PC pc,PCMGGalerkinType *galerkin) 1529 { 1530 PC_MG *mg = (PC_MG*)pc->data; 1531 1532 PetscFunctionBegin; 1533 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1534 *galerkin = mg->galerkin; 1535 PetscFunctionReturn(0); 1536 } 1537 1538 PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) 1539 { 1540 PC_MG *mg = (PC_MG *) pc->data; 1541 1542 PetscFunctionBegin; 1543 mg->adaptInterpolation = adapt; 1544 PetscFunctionReturn(0); 1545 } 1546 1547 PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) 1548 { 1549 PC_MG *mg = (PC_MG *) pc->data; 1550 1551 PetscFunctionBegin; 1552 *adapt = mg->adaptInterpolation; 1553 PetscFunctionReturn(0); 1554 } 1555 1556 PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) 1557 { 1558 PC_MG *mg = (PC_MG *) pc->data; 1559 1560 PetscFunctionBegin; 1561 mg->compatibleRelaxation = cr; 1562 PetscFunctionReturn(0); 1563 } 1564 1565 PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) 1566 { 1567 PC_MG *mg = (PC_MG *) pc->data; 1568 1569 PetscFunctionBegin; 1570 *cr = mg->compatibleRelaxation; 1571 PetscFunctionReturn(0); 1572 } 1573 1574 /*@ 1575 PCMGSetAdaptInterpolation - Adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated. 1576 1577 Logically Collective on PC 1578 1579 Input Parameters: 1580 + pc - the multigrid context 1581 - adapt - flag for adaptation of the interpolator 1582 1583 Options Database Keys: 1584 + -pc_mg_adapt_interp - Turn on adaptation 1585 . -pc_mg_adapt_interp_n <int> - The number of modes to use, should be divisible by dimension 1586 - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector 1587 1588 Level: intermediate 1589 1590 .keywords: MG, set, Galerkin 1591 .seealso: PCMGGetAdaptInterpolation(), PCMGSetGalerkin() 1592 @*/ 1593 PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) 1594 { 1595 PetscFunctionBegin; 1596 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1597 CHKERRQ(PetscTryMethod(pc,"PCMGSetAdaptInterpolation_C",(PC,PetscBool),(pc,adapt))); 1598 PetscFunctionReturn(0); 1599 } 1600 1601 /*@ 1602 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. 1603 1604 Not collective 1605 1606 Input Parameter: 1607 . pc - the multigrid context 1608 1609 Output Parameter: 1610 . adapt - flag for adaptation of the interpolator 1611 1612 Level: intermediate 1613 1614 .keywords: MG, set, Galerkin 1615 .seealso: PCMGSetAdaptInterpolation(), PCMGSetGalerkin() 1616 @*/ 1617 PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) 1618 { 1619 PetscFunctionBegin; 1620 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1621 PetscValidBoolPointer(adapt, 2); 1622 CHKERRQ(PetscUseMethod(pc,"PCMGGetAdaptInterpolation_C",(PC,PetscBool*),(pc,adapt))); 1623 PetscFunctionReturn(0); 1624 } 1625 1626 /*@ 1627 PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation. 1628 1629 Logically Collective on PC 1630 1631 Input Parameters: 1632 + pc - the multigrid context 1633 - cr - flag for compatible relaxation 1634 1635 Options Database Keys: 1636 . -pc_mg_adapt_cr - Turn on compatible relaxation 1637 1638 Level: intermediate 1639 1640 .keywords: MG, set, Galerkin 1641 .seealso: PCMGGetAdaptCR(), PCMGSetAdaptInterpolation(), PCMGSetGalerkin() 1642 @*/ 1643 PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) 1644 { 1645 PetscFunctionBegin; 1646 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1647 CHKERRQ(PetscTryMethod(pc,"PCMGSetAdaptCR_C",(PC,PetscBool),(pc,cr))); 1648 PetscFunctionReturn(0); 1649 } 1650 1651 /*@ 1652 PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation. 1653 1654 Not collective 1655 1656 Input Parameter: 1657 . pc - the multigrid context 1658 1659 Output Parameter: 1660 . cr - flag for compatible relaxaion 1661 1662 Level: intermediate 1663 1664 .keywords: MG, set, Galerkin 1665 .seealso: PCMGSetAdaptCR(), PCMGGetAdaptInterpolation(), PCMGSetGalerkin() 1666 @*/ 1667 PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) 1668 { 1669 PetscFunctionBegin; 1670 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1671 PetscValidBoolPointer(cr, 2); 1672 CHKERRQ(PetscUseMethod(pc,"PCMGGetAdaptCR_C",(PC,PetscBool*),(pc,cr))); 1673 PetscFunctionReturn(0); 1674 } 1675 1676 /*@ 1677 PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1678 on all levels. Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of 1679 pre- and post-smoothing steps. 1680 1681 Logically Collective on PC 1682 1683 Input Parameters: 1684 + mg - the multigrid context 1685 - n - the number of smoothing steps 1686 1687 Options Database Key: 1688 . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 1689 1690 Level: advanced 1691 1692 Notes: 1693 this does not set a value on the coarsest grid, since we assume that 1694 there is no separate smooth up on the coarsest grid. 1695 1696 .seealso: PCMGSetDistinctSmoothUp() 1697 @*/ 1698 PetscErrorCode PCMGSetNumberSmooth(PC pc,PetscInt n) 1699 { 1700 PC_MG *mg = (PC_MG*)pc->data; 1701 PC_MG_Levels **mglevels = mg->levels; 1702 PetscInt i,levels; 1703 1704 PetscFunctionBegin; 1705 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1706 PetscValidLogicalCollectiveInt(pc,n,2); 1707 PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1708 levels = mglevels[0]->levels; 1709 1710 for (i=1; i<levels; i++) { 1711 CHKERRQ(KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n)); 1712 CHKERRQ(KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n)); 1713 mg->default_smoothu = n; 1714 mg->default_smoothd = n; 1715 } 1716 PetscFunctionReturn(0); 1717 } 1718 1719 /*@ 1720 PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate KSP from the down (pre) smoother on all levels 1721 and adds the suffix _up to the options name 1722 1723 Logically Collective on PC 1724 1725 Input Parameters: 1726 . pc - the preconditioner context 1727 1728 Options Database Key: 1729 . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects 1730 1731 Level: advanced 1732 1733 Notes: 1734 this does not set a value on the coarsest grid, since we assume that 1735 there is no separate smooth up on the coarsest grid. 1736 1737 .seealso: PCMGSetNumberSmooth() 1738 @*/ 1739 PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1740 { 1741 PC_MG *mg = (PC_MG*)pc->data; 1742 PC_MG_Levels **mglevels = mg->levels; 1743 PetscInt i,levels; 1744 KSP subksp; 1745 1746 PetscFunctionBegin; 1747 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1748 PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1749 levels = mglevels[0]->levels; 1750 1751 for (i=1; i<levels; i++) { 1752 const char *prefix = NULL; 1753 /* make sure smoother up and down are different */ 1754 CHKERRQ(PCMGGetSmootherUp(pc,i,&subksp)); 1755 CHKERRQ(KSPGetOptionsPrefix(mglevels[i]->smoothd,&prefix)); 1756 CHKERRQ(KSPSetOptionsPrefix(subksp,prefix)); 1757 CHKERRQ(KSPAppendOptionsPrefix(subksp,"up_")); 1758 } 1759 PetscFunctionReturn(0); 1760 } 1761 1762 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1763 PetscErrorCode PCGetInterpolations_MG(PC pc,PetscInt *num_levels,Mat *interpolations[]) 1764 { 1765 PC_MG *mg = (PC_MG*)pc->data; 1766 PC_MG_Levels **mglevels = mg->levels; 1767 Mat *mat; 1768 PetscInt l; 1769 1770 PetscFunctionBegin; 1771 PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1772 CHKERRQ(PetscMalloc1(mg->nlevels,&mat)); 1773 for (l=1; l< mg->nlevels; l++) { 1774 mat[l-1] = mglevels[l]->interpolate; 1775 CHKERRQ(PetscObjectReference((PetscObject)mat[l-1])); 1776 } 1777 *num_levels = mg->nlevels; 1778 *interpolations = mat; 1779 PetscFunctionReturn(0); 1780 } 1781 1782 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1783 PetscErrorCode PCGetCoarseOperators_MG(PC pc,PetscInt *num_levels,Mat *coarseOperators[]) 1784 { 1785 PC_MG *mg = (PC_MG*)pc->data; 1786 PC_MG_Levels **mglevels = mg->levels; 1787 PetscInt l; 1788 Mat *mat; 1789 1790 PetscFunctionBegin; 1791 PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1792 CHKERRQ(PetscMalloc1(mg->nlevels,&mat)); 1793 for (l=0; l<mg->nlevels-1; l++) { 1794 CHKERRQ(KSPGetOperators(mglevels[l]->smoothd,NULL,&(mat[l]))); 1795 CHKERRQ(PetscObjectReference((PetscObject)mat[l])); 1796 } 1797 *num_levels = mg->nlevels; 1798 *coarseOperators = mat; 1799 PetscFunctionReturn(0); 1800 } 1801 1802 /*@C 1803 PCMGRegisterCoarseSpaceConstructor - Adds a method to the PCMG package for coarse space construction. 1804 1805 Not collective 1806 1807 Input Parameters: 1808 + name - name of the constructor 1809 - function - constructor routine 1810 1811 Notes: 1812 Calling sequence for the routine: 1813 $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, const Vec initGuess[], Vec **coarseSp) 1814 $ pc - The PC object 1815 $ l - The multigrid level, 0 is the coarse level 1816 $ dm - The DM for this level 1817 $ smooth - The level smoother 1818 $ Nc - The size of the coarse space 1819 $ initGuess - Basis for an initial guess for the space 1820 $ coarseSp - A basis for the computed coarse space 1821 1822 Level: advanced 1823 1824 .seealso: PCMGGetCoarseSpaceConstructor(), PCRegister() 1825 @*/ 1826 PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, const Vec[], Vec **)) 1827 { 1828 PetscFunctionBegin; 1829 CHKERRQ(PCInitializePackage()); 1830 CHKERRQ(PetscFunctionListAdd(&PCMGCoarseList,name,function)); 1831 PetscFunctionReturn(0); 1832 } 1833 1834 /*@C 1835 PCMGGetCoarseSpaceConstructor - Returns the given coarse space construction method. 1836 1837 Not collective 1838 1839 Input Parameter: 1840 . name - name of the constructor 1841 1842 Output Parameter: 1843 . function - constructor routine 1844 1845 Notes: 1846 Calling sequence for the routine: 1847 $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, const Vec initGuess[], Vec **coarseSp) 1848 $ pc - The PC object 1849 $ l - The multigrid level, 0 is the coarse level 1850 $ dm - The DM for this level 1851 $ smooth - The level smoother 1852 $ Nc - The size of the coarse space 1853 $ initGuess - Basis for an initial guess for the space 1854 $ coarseSp - A basis for the computed coarse space 1855 1856 Level: advanced 1857 1858 .seealso: PCMGRegisterCoarseSpaceConstructor(), PCRegister() 1859 @*/ 1860 PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, const Vec[], Vec **)) 1861 { 1862 PetscFunctionBegin; 1863 CHKERRQ(PetscFunctionListFind(PCMGCoarseList,name,function)); 1864 PetscFunctionReturn(0); 1865 } 1866 1867 /* ----------------------------------------------------------------------------------------*/ 1868 1869 /*MC 1870 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1871 information about the coarser grid matrices and restriction/interpolation operators. 1872 1873 Options Database Keys: 1874 + -pc_mg_levels <nlevels> - number of levels including finest 1875 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1876 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1877 . -pc_mg_log - log information about time spent on each level of the solver 1878 . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 1879 . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1880 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1881 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1882 to the Socket viewer for reading from MATLAB. 1883 - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 1884 to the binary output file called binaryoutput 1885 1886 Notes: 1887 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 1888 1889 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1890 1891 When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 1892 is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 1893 (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 1894 residual is computed at the end of each cycle. 1895 1896 Level: intermediate 1897 1898 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE 1899 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), 1900 PCMGSetDistinctSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 1901 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1902 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1903 M*/ 1904 1905 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1906 { 1907 PC_MG *mg; 1908 1909 PetscFunctionBegin; 1910 CHKERRQ(PetscNewLog(pc,&mg)); 1911 pc->data = mg; 1912 mg->nlevels = -1; 1913 mg->am = PC_MG_MULTIPLICATIVE; 1914 mg->galerkin = PC_MG_GALERKIN_NONE; 1915 mg->adaptInterpolation = PETSC_FALSE; 1916 mg->Nc = -1; 1917 mg->eigenvalue = -1; 1918 1919 pc->useAmat = PETSC_TRUE; 1920 1921 pc->ops->apply = PCApply_MG; 1922 pc->ops->applytranspose = PCApplyTranspose_MG; 1923 pc->ops->matapply = PCMatApply_MG; 1924 pc->ops->setup = PCSetUp_MG; 1925 pc->ops->reset = PCReset_MG; 1926 pc->ops->destroy = PCDestroy_MG; 1927 pc->ops->setfromoptions = PCSetFromOptions_MG; 1928 pc->ops->view = PCView_MG; 1929 1930 CHKERRQ(PetscObjectComposedDataRegister(&mg->eigenvalue)); 1931 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG)); 1932 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",PCMGGetLevels_MG)); 1933 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",PCMGSetLevels_MG)); 1934 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",PCGetInterpolations_MG)); 1935 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",PCGetCoarseOperators_MG)); 1936 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptInterpolation_C",PCMGSetAdaptInterpolation_MG)); 1937 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptInterpolation_C",PCMGGetAdaptInterpolation_MG)); 1938 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptCR_C",PCMGSetAdaptCR_MG)); 1939 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptCR_C",PCMGGetAdaptCR_MG)); 1940 PetscFunctionReturn(0); 1941 } 1942