1 2 /* 3 Defines the multigrid preconditioner interface. 4 */ 5 #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 6 #include <petscdm.h> 7 PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC,PetscBool*); 8 9 PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PCRichardsonConvergedReason *reason) 10 { 11 PC_MG *mg = (PC_MG*)pc->data; 12 PC_MG_Levels *mgc,*mglevels = *mglevelsin; 13 PetscErrorCode ierr; 14 PetscInt cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles; 15 16 PetscFunctionBegin; 17 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 18 ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr); /* pre-smooth */ 19 ierr = KSPCheckSolve(mglevels->smoothd,pc,mglevels->x);CHKERRQ(ierr); 20 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 21 if (mglevels->level) { /* not the coarsest grid */ 22 if (mglevels->eventresidual) {ierr = PetscLogEventBegin(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);} 23 ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr); 24 if (mglevels->eventresidual) {ierr = PetscLogEventEnd(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);} 25 26 /* if on finest level and have convergence criteria set */ 27 if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) { 28 PetscReal rnorm; 29 ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr); 30 if (rnorm <= mg->ttol) { 31 if (rnorm < mg->abstol) { 32 *reason = PCRICHARDSON_CONVERGED_ATOL; 33 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol);CHKERRQ(ierr); 34 } else { 35 *reason = PCRICHARDSON_CONVERGED_RTOL; 36 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n",(double)rnorm,(double)mg->ttol);CHKERRQ(ierr); 37 } 38 PetscFunctionReturn(0); 39 } 40 } 41 42 mgc = *(mglevelsin - 1); 43 if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 44 ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr); 45 if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 46 ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr); 47 while (cycles--) { 48 ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr); 49 } 50 if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 51 ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr); 52 if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 53 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 54 ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr); /* post smooth */ 55 ierr = KSPCheckSolve(mglevels->smoothu,pc,mglevels->x);CHKERRQ(ierr); 56 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 57 } 58 PetscFunctionReturn(0); 59 } 60 61 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) 62 { 63 PC_MG *mg = (PC_MG*)pc->data; 64 PC_MG_Levels **mglevels = mg->levels; 65 PetscErrorCode ierr; 66 PC tpc; 67 PetscBool changeu,changed; 68 PetscInt levels = mglevels[0]->levels,i; 69 70 PetscFunctionBegin; 71 /* When the DM is supplying the matrix then it will not exist until here */ 72 for (i=0; i<levels; i++) { 73 if (!mglevels[i]->A) { 74 ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr); 75 ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr); 76 } 77 } 78 79 ierr = KSPGetPC(mglevels[levels-1]->smoothd,&tpc);CHKERRQ(ierr); 80 ierr = PCPreSolveChangeRHS(tpc,&changed);CHKERRQ(ierr); 81 ierr = KSPGetPC(mglevels[levels-1]->smoothu,&tpc);CHKERRQ(ierr); 82 ierr = PCPreSolveChangeRHS(tpc,&changeu);CHKERRQ(ierr); 83 if (!changed && !changeu) { 84 ierr = VecDestroy(&mglevels[levels-1]->b);CHKERRQ(ierr); 85 mglevels[levels-1]->b = b; 86 } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 87 if (!mglevels[levels-1]->b) { 88 Vec *vec; 89 90 ierr = KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 91 mglevels[levels-1]->b = *vec; 92 ierr = PetscFree(vec);CHKERRQ(ierr); 93 } 94 ierr = VecCopy(b,mglevels[levels-1]->b);CHKERRQ(ierr); 95 } 96 mglevels[levels-1]->x = x; 97 98 mg->rtol = rtol; 99 mg->abstol = abstol; 100 mg->dtol = dtol; 101 if (rtol) { 102 /* compute initial residual norm for relative convergence test */ 103 PetscReal rnorm; 104 if (zeroguess) { 105 ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr); 106 } else { 107 ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr); 108 ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr); 109 } 110 mg->ttol = PetscMax(rtol*rnorm,abstol); 111 } else if (abstol) mg->ttol = abstol; 112 else mg->ttol = 0.0; 113 114 /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 115 stop prematurely due to small residual */ 116 for (i=1; i<levels; i++) { 117 ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 118 if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 119 /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */ 120 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 121 ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 122 } 123 } 124 125 *reason = (PCRichardsonConvergedReason)0; 126 for (i=0; i<its; i++) { 127 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr); 128 if (*reason) break; 129 } 130 if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 131 *outits = i; 132 if (!changed && !changeu) mglevels[levels-1]->b = NULL; 133 PetscFunctionReturn(0); 134 } 135 136 PetscErrorCode PCReset_MG(PC pc) 137 { 138 PC_MG *mg = (PC_MG*)pc->data; 139 PC_MG_Levels **mglevels = mg->levels; 140 PetscErrorCode ierr; 141 PetscInt i,n; 142 143 PetscFunctionBegin; 144 if (mglevels) { 145 n = mglevels[0]->levels; 146 for (i=0; i<n-1; i++) { 147 ierr = VecDestroy(&mglevels[i+1]->r);CHKERRQ(ierr); 148 ierr = VecDestroy(&mglevels[i]->b);CHKERRQ(ierr); 149 ierr = VecDestroy(&mglevels[i]->x);CHKERRQ(ierr); 150 ierr = MatDestroy(&mglevels[i+1]->restrct);CHKERRQ(ierr); 151 ierr = MatDestroy(&mglevels[i+1]->interpolate);CHKERRQ(ierr); 152 ierr = MatDestroy(&mglevels[i+1]->inject);CHKERRQ(ierr); 153 ierr = VecDestroy(&mglevels[i+1]->rscale);CHKERRQ(ierr); 154 } 155 /* this is not null only if the smoother on the finest level 156 changes the rhs during PreSolve */ 157 ierr = VecDestroy(&mglevels[n-1]->b);CHKERRQ(ierr); 158 159 for (i=0; i<n; i++) { 160 ierr = MatDestroy(&mglevels[i]->A);CHKERRQ(ierr); 161 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 162 ierr = KSPReset(mglevels[i]->smoothd);CHKERRQ(ierr); 163 } 164 ierr = KSPReset(mglevels[i]->smoothu);CHKERRQ(ierr); 165 } 166 } 167 PetscFunctionReturn(0); 168 } 169 170 PetscErrorCode PCMGSetLevels_MG(PC pc,PetscInt levels,MPI_Comm *comms) 171 { 172 PetscErrorCode ierr; 173 PC_MG *mg = (PC_MG*)pc->data; 174 MPI_Comm comm; 175 PC_MG_Levels **mglevels = mg->levels; 176 PCMGType mgtype = mg->am; 177 PetscInt mgctype = (PetscInt) PC_MG_CYCLE_V; 178 PetscInt i; 179 PetscMPIInt size; 180 const char *prefix; 181 PC ipc; 182 PetscInt n; 183 184 PetscFunctionBegin; 185 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 186 PetscValidLogicalCollectiveInt(pc,levels,2); 187 if (mg->nlevels == levels) PetscFunctionReturn(0); 188 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 189 if (mglevels) { 190 mgctype = mglevels[0]->cycles; 191 /* changing the number of levels so free up the previous stuff */ 192 ierr = PCReset_MG(pc);CHKERRQ(ierr); 193 n = mglevels[0]->levels; 194 for (i=0; i<n; i++) { 195 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 196 ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr); 197 } 198 ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr); 199 ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); 200 } 201 ierr = PetscFree(mg->levels);CHKERRQ(ierr); 202 } 203 204 mg->nlevels = levels; 205 206 ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr); 207 ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr); 208 209 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 210 211 mg->stageApply = 0; 212 for (i=0; i<levels; i++) { 213 ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr); 214 215 mglevels[i]->level = i; 216 mglevels[i]->levels = levels; 217 mglevels[i]->cycles = mgctype; 218 mg->default_smoothu = 2; 219 mg->default_smoothd = 2; 220 mglevels[i]->eventsmoothsetup = 0; 221 mglevels[i]->eventsmoothsolve = 0; 222 mglevels[i]->eventresidual = 0; 223 mglevels[i]->eventinterprestrict = 0; 224 225 if (comms) comm = comms[i]; 226 ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr); 227 ierr = KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure);CHKERRQ(ierr); 228 ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr); 229 ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr); 230 ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level);CHKERRQ(ierr); 231 if (i || levels == 1) { 232 char tprefix[128]; 233 234 ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr); 235 ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr); 236 ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr); 237 ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr); 238 ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr); 239 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);CHKERRQ(ierr); 240 241 sprintf(tprefix,"mg_levels_%d_",(int)i); 242 ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr); 243 } else { 244 ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr); 245 246 /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 247 ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr); 248 ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr); 249 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 250 if (size > 1) { 251 ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr); 252 } else { 253 ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr); 254 } 255 ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 256 } 257 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr); 258 259 mglevels[i]->smoothu = mglevels[i]->smoothd; 260 mg->rtol = 0.0; 261 mg->abstol = 0.0; 262 mg->dtol = 0.0; 263 mg->ttol = 0.0; 264 mg->cyclesperpcapply = 1; 265 } 266 mg->levels = mglevels; 267 ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr); 268 PetscFunctionReturn(0); 269 } 270 271 /*@C 272 PCMGSetLevels - Sets the number of levels to use with MG. 273 Must be called before any other MG routine. 274 275 Logically Collective on PC 276 277 Input Parameters: 278 + pc - the preconditioner context 279 . levels - the number of levels 280 - comms - optional communicators for each level; this is to allow solving the coarser problems 281 on smaller sets of processors. 282 283 Level: intermediate 284 285 Notes: 286 If the number of levels is one then the multigrid uses the -mg_levels prefix 287 for setting the level options rather than the -mg_coarse prefix. 288 289 .seealso: PCMGSetType(), PCMGGetLevels() 290 @*/ 291 PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms) 292 { 293 PetscErrorCode ierr; 294 295 PetscFunctionBegin; 296 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 297 if (comms) PetscValidPointer(comms,3); 298 ierr = PetscTryMethod(pc,"PCMGSetLevels_C",(PC,PetscInt,MPI_Comm*),(pc,levels,comms));CHKERRQ(ierr); 299 PetscFunctionReturn(0); 300 } 301 302 303 PetscErrorCode PCDestroy_MG(PC pc) 304 { 305 PetscErrorCode ierr; 306 PC_MG *mg = (PC_MG*)pc->data; 307 PC_MG_Levels **mglevels = mg->levels; 308 PetscInt i,n; 309 310 PetscFunctionBegin; 311 ierr = PCReset_MG(pc);CHKERRQ(ierr); 312 if (mglevels) { 313 n = mglevels[0]->levels; 314 for (i=0; i<n; i++) { 315 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 316 ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr); 317 } 318 ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr); 319 ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); 320 } 321 ierr = PetscFree(mg->levels);CHKERRQ(ierr); 322 } 323 ierr = PetscFree(pc->data);CHKERRQ(ierr); 324 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",NULL);CHKERRQ(ierr); 325 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",NULL);CHKERRQ(ierr); 326 PetscFunctionReturn(0); 327 } 328 329 330 331 extern PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**); 332 extern PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**); 333 extern PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**); 334 335 /* 336 PCApply_MG - Runs either an additive, multiplicative, Kaskadic 337 or full cycle of multigrid. 338 339 Note: 340 A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 341 */ 342 static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x) 343 { 344 PC_MG *mg = (PC_MG*)pc->data; 345 PC_MG_Levels **mglevels = mg->levels; 346 PetscErrorCode ierr; 347 PC tpc; 348 PetscInt levels = mglevels[0]->levels,i; 349 PetscBool changeu,changed; 350 351 PetscFunctionBegin; 352 if (mg->stageApply) {ierr = PetscLogStagePush(mg->stageApply);CHKERRQ(ierr);} 353 /* When the DM is supplying the matrix then it will not exist until here */ 354 for (i=0; i<levels; i++) { 355 if (!mglevels[i]->A) { 356 ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr); 357 ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr); 358 } 359 } 360 361 ierr = KSPGetPC(mglevels[levels-1]->smoothd,&tpc);CHKERRQ(ierr); 362 ierr = PCPreSolveChangeRHS(tpc,&changed);CHKERRQ(ierr); 363 ierr = KSPGetPC(mglevels[levels-1]->smoothu,&tpc);CHKERRQ(ierr); 364 ierr = PCPreSolveChangeRHS(tpc,&changeu);CHKERRQ(ierr); 365 if (!changeu && !changed) { 366 ierr = VecDestroy(&mglevels[levels-1]->b);CHKERRQ(ierr); 367 mglevels[levels-1]->b = b; 368 } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */ 369 if (!mglevels[levels-1]->b) { 370 Vec *vec; 371 372 ierr = KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 373 mglevels[levels-1]->b = *vec; 374 ierr = PetscFree(vec);CHKERRQ(ierr); 375 } 376 ierr = VecCopy(b,mglevels[levels-1]->b);CHKERRQ(ierr); 377 } 378 mglevels[levels-1]->x = x; 379 380 if (mg->am == PC_MG_MULTIPLICATIVE) { 381 ierr = VecSet(x,0.0);CHKERRQ(ierr); 382 for (i=0; i<mg->cyclesperpcapply; i++) { 383 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,NULL);CHKERRQ(ierr); 384 } 385 } else if (mg->am == PC_MG_ADDITIVE) { 386 ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr); 387 } else if (mg->am == PC_MG_KASKADE) { 388 ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr); 389 } else { 390 ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr); 391 } 392 if (mg->stageApply) {ierr = PetscLogStagePop();CHKERRQ(ierr);} 393 if (!changeu && !changed) mglevels[levels-1]->b = NULL; 394 PetscFunctionReturn(0); 395 } 396 397 398 PetscErrorCode PCSetFromOptions_MG(PetscOptionItems *PetscOptionsObject,PC pc) 399 { 400 PetscErrorCode ierr; 401 PetscInt levels,cycles; 402 PetscBool flg; 403 PC_MG *mg = (PC_MG*)pc->data; 404 PC_MG_Levels **mglevels; 405 PCMGType mgtype; 406 PCMGCycleType mgctype; 407 PCMGGalerkinType gtype; 408 409 PetscFunctionBegin; 410 levels = PetscMax(mg->nlevels,1); 411 ierr = PetscOptionsHead(PetscOptionsObject,"Multigrid options");CHKERRQ(ierr); 412 ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr); 413 if (!flg && !mg->levels && pc->dm) { 414 ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr); 415 levels++; 416 mg->usedmfornumberoflevels = PETSC_TRUE; 417 } 418 ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr); 419 mglevels = mg->levels; 420 421 mgctype = (PCMGCycleType) mglevels[0]->cycles; 422 ierr = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr); 423 if (flg) { 424 ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr); 425 } 426 gtype = mg->galerkin; 427 ierr = PetscOptionsEnum("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",PCMGGalerkinTypes,(PetscEnum)gtype,(PetscEnum*)>ype,&flg);CHKERRQ(ierr); 428 if (flg) { 429 ierr = PCMGSetGalerkin(pc,gtype);CHKERRQ(ierr); 430 } 431 flg = PETSC_FALSE; 432 ierr = PetscOptionsBool("-pc_mg_distinct_smoothup","Create seperate smoothup KSP and append the prefix _up","PCMGSetDistinctSmoothUp",PETSC_FALSE,&flg,NULL);CHKERRQ(ierr); 433 if (flg) { 434 ierr = PCMGSetDistinctSmoothUp(pc);CHKERRQ(ierr); 435 } 436 mgtype = mg->am; 437 ierr = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr); 438 if (flg) { 439 ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr); 440 } 441 if (mg->am == PC_MG_MULTIPLICATIVE) { 442 ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGMultiplicativeSetCycles",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr); 443 if (flg) { 444 ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr); 445 } 446 } 447 flg = PETSC_FALSE; 448 ierr = PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL);CHKERRQ(ierr); 449 if (flg) { 450 PetscInt i; 451 char eventname[128]; 452 453 levels = mglevels[0]->levels; 454 for (i=0; i<levels; i++) { 455 sprintf(eventname,"MGSetup Level %d",(int)i); 456 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup);CHKERRQ(ierr); 457 sprintf(eventname,"MGSmooth Level %d",(int)i); 458 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve);CHKERRQ(ierr); 459 if (i) { 460 sprintf(eventname,"MGResid Level %d",(int)i); 461 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual);CHKERRQ(ierr); 462 sprintf(eventname,"MGInterp Level %d",(int)i); 463 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict);CHKERRQ(ierr); 464 } 465 } 466 467 #if defined(PETSC_USE_LOG) 468 { 469 const char *sname = "MG Apply"; 470 PetscStageLog stageLog; 471 PetscInt st; 472 473 ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr); 474 for (st = 0; st < stageLog->numStages; ++st) { 475 PetscBool same; 476 477 ierr = PetscStrcmp(stageLog->stageInfo[st].name, sname, &same);CHKERRQ(ierr); 478 if (same) mg->stageApply = st; 479 } 480 if (!mg->stageApply) { 481 ierr = PetscLogStageRegister(sname, &mg->stageApply);CHKERRQ(ierr); 482 } 483 } 484 #endif 485 } 486 ierr = PetscOptionsTail();CHKERRQ(ierr); 487 PetscFunctionReturn(0); 488 } 489 490 const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0}; 491 const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0}; 492 const char *const PCMGGalerkinTypes[] = {"both","pmat","mat","none","external","PCMGGalerkinType","PC_MG_GALERKIN",0}; 493 494 #include <petscdraw.h> 495 PetscErrorCode PCView_MG(PC pc,PetscViewer viewer) 496 { 497 PC_MG *mg = (PC_MG*)pc->data; 498 PC_MG_Levels **mglevels = mg->levels; 499 PetscErrorCode ierr; 500 PetscInt levels = mglevels ? mglevels[0]->levels : 0,i; 501 PetscBool iascii,isbinary,isdraw; 502 503 PetscFunctionBegin; 504 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 505 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr); 506 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 507 if (iascii) { 508 const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 509 ierr = PetscViewerASCIIPrintf(viewer," type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename);CHKERRQ(ierr); 510 if (mg->am == PC_MG_MULTIPLICATIVE) { 511 ierr = PetscViewerASCIIPrintf(viewer," Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr); 512 } 513 if (mg->galerkin == PC_MG_GALERKIN_BOTH) { 514 ierr = PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 515 } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) { 516 ierr = PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices for pmat\n");CHKERRQ(ierr); 517 } else if (mg->galerkin == PC_MG_GALERKIN_MAT) { 518 ierr = PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices for mat\n");CHKERRQ(ierr); 519 } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) { 520 ierr = PetscViewerASCIIPrintf(viewer," Using externally compute Galerkin coarse grid matrices\n");CHKERRQ(ierr); 521 } else { 522 ierr = PetscViewerASCIIPrintf(viewer," Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 523 } 524 if (mg->view){ 525 ierr = (*mg->view)(pc,viewer);CHKERRQ(ierr); 526 } 527 for (i=0; i<levels; i++) { 528 if (!i) { 529 ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i);CHKERRQ(ierr); 530 } else { 531 ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr); 532 } 533 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 534 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 535 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 536 if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 537 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr); 538 } else if (i) { 539 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr); 540 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 541 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 542 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 543 } 544 } 545 } else if (isbinary) { 546 for (i=levels-1; i>=0; i--) { 547 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 548 if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) { 549 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 550 } 551 } 552 } else if (isdraw) { 553 PetscDraw draw; 554 PetscReal x,w,y,bottom,th; 555 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 556 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 557 ierr = PetscDrawStringGetSize(draw,NULL,&th);CHKERRQ(ierr); 558 bottom = y - th; 559 for (i=levels-1; i>=0; i--) { 560 if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 561 ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr); 562 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 563 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 564 } else { 565 w = 0.5*PetscMin(1.0-x,x); 566 ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr); 567 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 568 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 569 ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr); 570 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 571 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 572 } 573 ierr = PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL);CHKERRQ(ierr); 574 bottom -= th; 575 } 576 } 577 PetscFunctionReturn(0); 578 } 579 580 #include <petsc/private/dmimpl.h> 581 #include <petsc/private/kspimpl.h> 582 583 /* 584 Calls setup for the KSP on each level 585 */ 586 PetscErrorCode PCSetUp_MG(PC pc) 587 { 588 PC_MG *mg = (PC_MG*)pc->data; 589 PC_MG_Levels **mglevels = mg->levels; 590 PetscErrorCode ierr; 591 PetscInt i,n; 592 PC cpc; 593 PetscBool dump = PETSC_FALSE,opsset,use_amat,missinginterpolate = PETSC_FALSE; 594 Mat dA,dB; 595 Vec tvec; 596 DM *dms; 597 PetscViewer viewer = 0; 598 PetscBool dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE; 599 600 PetscFunctionBegin; 601 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels with PCMGSetLevels() before setting up"); 602 n = mglevels[0]->levels; 603 /* FIX: Move this to PCSetFromOptions_MG? */ 604 if (mg->usedmfornumberoflevels) { 605 PetscInt levels; 606 ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr); 607 levels++; 608 if (levels > n) { /* the problem is now being solved on a finer grid */ 609 ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr); 610 n = levels; 611 ierr = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 612 mglevels = mg->levels; 613 } 614 } 615 ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr); 616 617 618 /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 619 /* so use those from global PC */ 620 /* Is this what we always want? What if user wants to keep old one? */ 621 ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr); 622 if (opsset) { 623 Mat mmat; 624 ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat);CHKERRQ(ierr); 625 if (mmat == pc->pmat) opsset = PETSC_FALSE; 626 } 627 628 if (!opsset) { 629 ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr); 630 if (use_amat) { 631 ierr = PetscInfo(pc,"Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr); 632 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat);CHKERRQ(ierr); 633 } else { 634 ierr = PetscInfo(pc,"Using matrix (pmat) operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr); 635 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat);CHKERRQ(ierr); 636 } 637 } 638 639 for (i=n-1; i>0; i--) { 640 if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 641 missinginterpolate = PETSC_TRUE; 642 continue; 643 } 644 } 645 646 ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB);CHKERRQ(ierr); 647 if (dA == dB) dAeqdB = PETSC_TRUE; 648 if ((mg->galerkin == PC_MG_GALERKIN_NONE) || (((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_MAT)) && !dAeqdB)) { 649 needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */ 650 } 651 652 653 /* 654 Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 655 Skipping for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 656 */ 657 if (missinginterpolate && pc->dm && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) { 658 /* construct the interpolation from the DMs */ 659 Mat p; 660 Vec rscale; 661 ierr = PetscMalloc1(n,&dms);CHKERRQ(ierr); 662 dms[n-1] = pc->dm; 663 /* Separately create them so we do not get DMKSP interference between levels */ 664 for (i=n-2; i>-1; i--) {ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr);} 665 /* 666 Force the mat type of coarse level operator to be AIJ because usually we want to use LU for coarse level. 667 Notice that it can be overwritten by -mat_type because KSPSetUp() reads command line options. 668 But it is safe to use -dm_mat_type. 669 670 The mat type should not be hardcoded like this, we need to find a better way. 671 ierr = DMSetMatType(dms[0],MATAIJ);CHKERRQ(ierr); 672 */ 673 for (i=n-2; i>-1; i--) { 674 DMKSP kdm; 675 PetscBool dmhasrestrict, dmhasinject; 676 ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr); 677 if (!needRestricts) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);} 678 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 679 ierr = KSPSetDM(mglevels[i]->smoothu,dms[i]);CHKERRQ(ierr); 680 if (!needRestricts) {ierr = KSPSetDMActive(mglevels[i]->smoothu,PETSC_FALSE);CHKERRQ(ierr);} 681 } 682 ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr); 683 /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 684 * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 685 kdm->ops->computerhs = NULL; 686 kdm->rhsctx = NULL; 687 if (!mglevels[i+1]->interpolate) { 688 ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr); 689 ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr); 690 if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);} 691 ierr = VecDestroy(&rscale);CHKERRQ(ierr); 692 ierr = MatDestroy(&p);CHKERRQ(ierr); 693 } 694 ierr = DMHasCreateRestriction(dms[i],&dmhasrestrict);CHKERRQ(ierr); 695 if (dmhasrestrict && !mglevels[i+1]->restrct){ 696 ierr = DMCreateRestriction(dms[i],dms[i+1],&p);CHKERRQ(ierr); 697 ierr = PCMGSetRestriction(pc,i+1,p);CHKERRQ(ierr); 698 ierr = MatDestroy(&p);CHKERRQ(ierr); 699 } 700 ierr = DMHasCreateInjection(dms[i],&dmhasinject);CHKERRQ(ierr); 701 if (dmhasinject && !mglevels[i+1]->inject){ 702 ierr = DMCreateInjection(dms[i],dms[i+1],&p);CHKERRQ(ierr); 703 ierr = PCMGSetInjection(pc,i+1,p);CHKERRQ(ierr); 704 ierr = MatDestroy(&p);CHKERRQ(ierr); 705 } 706 } 707 708 for (i=n-2; i>-1; i--) {ierr = DMDestroy(&dms[i]);CHKERRQ(ierr);} 709 ierr = PetscFree(dms);CHKERRQ(ierr); 710 } 711 712 if (pc->dm && !pc->setupcalled) { 713 /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */ 714 ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr); 715 ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr); 716 if (mglevels[n-1]->smoothd != mglevels[n-1]->smoothu) { 717 ierr = KSPSetDM(mglevels[n-1]->smoothu,pc->dm);CHKERRQ(ierr); 718 ierr = KSPSetDMActive(mglevels[n-1]->smoothu,PETSC_FALSE);CHKERRQ(ierr); 719 } 720 } 721 722 if (mg->galerkin < PC_MG_GALERKIN_NONE) { 723 Mat A,B; 724 PetscBool doA = PETSC_FALSE,doB = PETSC_FALSE; 725 MatReuse reuse = MAT_INITIAL_MATRIX; 726 727 if ((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_BOTH)) doB = PETSC_TRUE; 728 if ((mg->galerkin == PC_MG_GALERKIN_MAT) || ((mg->galerkin == PC_MG_GALERKIN_BOTH) && (dA != dB))) doA = PETSC_TRUE; 729 if (pc->setupcalled) reuse = MAT_REUSE_MATRIX; 730 for (i=n-2; i>-1; i--) { 731 if (!mglevels[i+1]->restrct && !mglevels[i+1]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must provide interpolation or restriction for each MG level except level 0"); 732 if (!mglevels[i+1]->interpolate) { 733 ierr = PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct);CHKERRQ(ierr); 734 } 735 if (!mglevels[i+1]->restrct) { 736 ierr = PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate);CHKERRQ(ierr); 737 } 738 if (reuse == MAT_REUSE_MATRIX) { 739 ierr = KSPGetOperators(mglevels[i]->smoothd,&A,&B);CHKERRQ(ierr); 740 } 741 if (doA) { 742 ierr = MatGalerkin(mglevels[i+1]->restrct,dA,mglevels[i+1]->interpolate,reuse,1.0,&A);CHKERRQ(ierr); 743 } 744 if (doB) { 745 ierr = MatGalerkin(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,reuse,1.0,&B);CHKERRQ(ierr); 746 } 747 /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */ 748 if (!doA && dAeqdB) { 749 if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);} 750 A = B; 751 } else if (!doA && reuse == MAT_INITIAL_MATRIX ) { 752 ierr = KSPGetOperators(mglevels[i]->smoothd,&A,NULL);CHKERRQ(ierr); 753 ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr); 754 } 755 if (!doB && dAeqdB) { 756 if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);} 757 B = A; 758 } else if (!doB && reuse == MAT_INITIAL_MATRIX) { 759 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B);CHKERRQ(ierr); 760 ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr); 761 } 762 if (reuse == MAT_INITIAL_MATRIX) { 763 ierr = KSPSetOperators(mglevels[i]->smoothd,A,B);CHKERRQ(ierr); 764 ierr = PetscObjectDereference((PetscObject)A);CHKERRQ(ierr); 765 ierr = PetscObjectDereference((PetscObject)B);CHKERRQ(ierr); 766 } 767 dA = A; 768 dB = B; 769 } 770 } 771 if (needRestricts && pc->dm && pc->dm->x) { 772 /* need to restrict Jacobian location to coarser meshes for evaluation */ 773 for (i=n-2; i>-1; i--) { 774 Mat R; 775 Vec rscale; 776 if (!mglevels[i]->smoothd->dm->x) { 777 Vec *vecs; 778 ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr); 779 mglevels[i]->smoothd->dm->x = vecs[0]; 780 ierr = PetscFree(vecs);CHKERRQ(ierr); 781 } 782 ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr); 783 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 784 ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr); 785 ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr); 786 } 787 } 788 if (needRestricts && pc->dm) { 789 for (i=n-2; i>=0; i--) { 790 DM dmfine,dmcoarse; 791 Mat Restrict,Inject; 792 Vec rscale; 793 ierr = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr); 794 ierr = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr); 795 ierr = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr); 796 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 797 ierr = PCMGGetInjection(pc,i+1,&Inject);CHKERRQ(ierr); 798 ierr = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr); 799 } 800 } 801 802 if (!pc->setupcalled) { 803 for (i=0; i<n; i++) { 804 ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr); 805 } 806 for (i=1; i<n; i++) { 807 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 808 ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr); 809 } 810 } 811 /* insure that if either interpolation or restriction is set the other other one is set */ 812 for (i=1; i<n; i++) { 813 ierr = PCMGGetInterpolation(pc,i,NULL);CHKERRQ(ierr); 814 ierr = PCMGGetRestriction(pc,i,NULL);CHKERRQ(ierr); 815 } 816 for (i=0; i<n-1; i++) { 817 if (!mglevels[i]->b) { 818 Vec *vec; 819 ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 820 ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr); 821 ierr = VecDestroy(vec);CHKERRQ(ierr); 822 ierr = PetscFree(vec);CHKERRQ(ierr); 823 } 824 if (!mglevels[i]->r && i) { 825 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 826 ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr); 827 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 828 } 829 if (!mglevels[i]->x) { 830 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 831 ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr); 832 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 833 } 834 } 835 if (n != 1 && !mglevels[n-1]->r) { 836 /* PCMGSetR() on the finest level if user did not supply it */ 837 Vec *vec; 838 ierr = KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 839 ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr); 840 ierr = VecDestroy(vec);CHKERRQ(ierr); 841 ierr = PetscFree(vec);CHKERRQ(ierr); 842 } 843 } 844 845 if (pc->dm) { 846 /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 847 for (i=0; i<n-1; i++) { 848 if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 849 } 850 } 851 852 for (i=1; i<n; i++) { 853 if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1){ 854 /* if doing only down then initial guess is zero */ 855 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 856 } 857 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 858 ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr); 859 if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { 860 pc->failedreason = PC_SUBPC_ERROR; 861 } 862 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 863 if (!mglevels[i]->residual) { 864 Mat mat; 865 ierr = KSPGetOperators(mglevels[i]->smoothd,&mat,NULL);CHKERRQ(ierr); 866 ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr); 867 } 868 } 869 for (i=1; i<n; i++) { 870 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 871 Mat downmat,downpmat; 872 873 /* check if operators have been set for up, if not use down operators to set them */ 874 ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr); 875 if (!opsset) { 876 ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr); 877 ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr); 878 } 879 880 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr); 881 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 882 ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr); 883 if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) { 884 pc->failedreason = PC_SUBPC_ERROR; 885 } 886 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 887 } 888 } 889 890 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 891 ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr); 892 if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { 893 pc->failedreason = PC_SUBPC_ERROR; 894 } 895 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 896 897 /* 898 Dump the interpolation/restriction matrices plus the 899 Jacobian/stiffness on each level. This allows MATLAB users to 900 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 901 902 Only support one or the other at the same time. 903 */ 904 #if defined(PETSC_USE_SOCKET_VIEWER) 905 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr); 906 if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 907 dump = PETSC_FALSE; 908 #endif 909 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr); 910 if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 911 912 if (viewer) { 913 for (i=1; i<n; i++) { 914 ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr); 915 } 916 for (i=0; i<n; i++) { 917 ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr); 918 ierr = MatView(pc->mat,viewer);CHKERRQ(ierr); 919 } 920 } 921 PetscFunctionReturn(0); 922 } 923 924 /* -------------------------------------------------------------------------------------*/ 925 926 PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) 927 { 928 PC_MG *mg = (PC_MG *) pc->data; 929 930 PetscFunctionBegin; 931 *levels = mg->nlevels; 932 PetscFunctionReturn(0); 933 } 934 935 /*@ 936 PCMGGetLevels - Gets the number of levels to use with MG. 937 938 Not Collective 939 940 Input Parameter: 941 . pc - the preconditioner context 942 943 Output parameter: 944 . levels - the number of levels 945 946 Level: advanced 947 948 .seealso: PCMGSetLevels() 949 @*/ 950 PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels) 951 { 952 PetscErrorCode ierr; 953 954 PetscFunctionBegin; 955 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 956 PetscValidIntPointer(levels,2); 957 *levels = 0; 958 ierr = PetscTryMethod(pc,"PCMGGetLevels_C",(PC,PetscInt*),(pc,levels));CHKERRQ(ierr); 959 PetscFunctionReturn(0); 960 } 961 962 /*@ 963 PCMGSetType - Determines the form of multigrid to use: 964 multiplicative, additive, full, or the Kaskade algorithm. 965 966 Logically Collective on PC 967 968 Input Parameters: 969 + pc - the preconditioner context 970 - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 971 PC_MG_FULL, PC_MG_KASKADE 972 973 Options Database Key: 974 . -pc_mg_type <form> - Sets <form>, one of multiplicative, 975 additive, full, kaskade 976 977 Level: advanced 978 979 .seealso: PCMGSetLevels() 980 @*/ 981 PetscErrorCode PCMGSetType(PC pc,PCMGType form) 982 { 983 PC_MG *mg = (PC_MG*)pc->data; 984 985 PetscFunctionBegin; 986 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 987 PetscValidLogicalCollectiveEnum(pc,form,2); 988 mg->am = form; 989 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 990 else pc->ops->applyrichardson = NULL; 991 PetscFunctionReturn(0); 992 } 993 994 /*@ 995 PCMGGetType - Determines the form of multigrid to use: 996 multiplicative, additive, full, or the Kaskade algorithm. 997 998 Logically Collective on PC 999 1000 Input Parameter: 1001 . pc - the preconditioner context 1002 1003 Output Parameter: 1004 . type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE 1005 1006 1007 Level: advanced 1008 1009 .seealso: PCMGSetLevels() 1010 @*/ 1011 PetscErrorCode PCMGGetType(PC pc,PCMGType *type) 1012 { 1013 PC_MG *mg = (PC_MG*)pc->data; 1014 1015 PetscFunctionBegin; 1016 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1017 *type = mg->am; 1018 PetscFunctionReturn(0); 1019 } 1020 1021 /*@ 1022 PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 1023 complicated cycling. 1024 1025 Logically Collective on PC 1026 1027 Input Parameters: 1028 + pc - the multigrid context 1029 - n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W 1030 1031 Options Database Key: 1032 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1033 1034 Level: advanced 1035 1036 .seealso: PCMGSetCycleTypeOnLevel() 1037 @*/ 1038 PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n) 1039 { 1040 PC_MG *mg = (PC_MG*)pc->data; 1041 PC_MG_Levels **mglevels = mg->levels; 1042 PetscInt i,levels; 1043 1044 PetscFunctionBegin; 1045 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1046 PetscValidLogicalCollectiveEnum(pc,n,2); 1047 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1048 levels = mglevels[0]->levels; 1049 for (i=0; i<levels; i++) mglevels[i]->cycles = n; 1050 PetscFunctionReturn(0); 1051 } 1052 1053 /*@ 1054 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 1055 of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 1056 1057 Logically Collective on PC 1058 1059 Input Parameters: 1060 + pc - the multigrid context 1061 - n - number of cycles (default is 1) 1062 1063 Options Database Key: 1064 . -pc_mg_multiplicative_cycles n 1065 1066 Level: advanced 1067 1068 Notes: 1069 This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 1070 1071 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType() 1072 @*/ 1073 PetscErrorCode PCMGMultiplicativeSetCycles(PC pc,PetscInt n) 1074 { 1075 PC_MG *mg = (PC_MG*)pc->data; 1076 1077 PetscFunctionBegin; 1078 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1079 PetscValidLogicalCollectiveInt(pc,n,2); 1080 mg->cyclesperpcapply = n; 1081 PetscFunctionReturn(0); 1082 } 1083 1084 PetscErrorCode PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use) 1085 { 1086 PC_MG *mg = (PC_MG*)pc->data; 1087 1088 PetscFunctionBegin; 1089 mg->galerkin = use; 1090 PetscFunctionReturn(0); 1091 } 1092 1093 /*@ 1094 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 1095 finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1096 1097 Logically Collective on PC 1098 1099 Input Parameters: 1100 + pc - the multigrid context 1101 - use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE 1102 1103 Options Database Key: 1104 . -pc_mg_galerkin <both,pmat,mat,none> 1105 1106 Level: intermediate 1107 1108 Notes: 1109 Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not 1110 use the PCMG construction of the coarser grids. 1111 1112 .seealso: PCMGGetGalerkin(), PCMGGalerkinType 1113 1114 @*/ 1115 PetscErrorCode PCMGSetGalerkin(PC pc,PCMGGalerkinType use) 1116 { 1117 PetscErrorCode ierr; 1118 1119 PetscFunctionBegin; 1120 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1121 ierr = PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PCMGGalerkinType),(pc,use));CHKERRQ(ierr); 1122 PetscFunctionReturn(0); 1123 } 1124 1125 /*@ 1126 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 1127 A_i-1 = r_i * A_i * p_i 1128 1129 Not Collective 1130 1131 Input Parameter: 1132 . pc - the multigrid context 1133 1134 Output Parameter: 1135 . galerkin - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, PC_MG_GALERKIN_NONE, or PC_MG_GALERKIN_EXTERNAL 1136 1137 Level: intermediate 1138 1139 .seealso: PCMGSetGalerkin(), PCMGGalerkinType 1140 1141 @*/ 1142 PetscErrorCode PCMGGetGalerkin(PC pc,PCMGGalerkinType *galerkin) 1143 { 1144 PC_MG *mg = (PC_MG*)pc->data; 1145 1146 PetscFunctionBegin; 1147 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1148 *galerkin = mg->galerkin; 1149 PetscFunctionReturn(0); 1150 } 1151 1152 /*@ 1153 PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use 1154 on all levels. Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of 1155 pre- and post-smoothing steps. 1156 1157 Logically Collective on PC 1158 1159 Input Parameters: 1160 + mg - the multigrid context 1161 - n - the number of smoothing steps 1162 1163 Options Database Key: 1164 . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps 1165 1166 Level: advanced 1167 1168 Notes: 1169 this does not set a value on the coarsest grid, since we assume that 1170 there is no separate smooth up on the coarsest grid. 1171 1172 .seealso: PCMGSetDistinctSmoothUp() 1173 @*/ 1174 PetscErrorCode PCMGSetNumberSmooth(PC pc,PetscInt n) 1175 { 1176 PC_MG *mg = (PC_MG*)pc->data; 1177 PC_MG_Levels **mglevels = mg->levels; 1178 PetscErrorCode ierr; 1179 PetscInt i,levels; 1180 1181 PetscFunctionBegin; 1182 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1183 PetscValidLogicalCollectiveInt(pc,n,2); 1184 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1185 levels = mglevels[0]->levels; 1186 1187 for (i=1; i<levels; i++) { 1188 ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1189 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1190 mg->default_smoothu = n; 1191 mg->default_smoothd = n; 1192 } 1193 PetscFunctionReturn(0); 1194 } 1195 1196 /*@ 1197 PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a seperate KSP from the down (pre) smoother on all levels 1198 and adds the suffix _up to the options name 1199 1200 Logically Collective on PC 1201 1202 Input Parameters: 1203 . pc - the preconditioner context 1204 1205 Options Database Key: 1206 . -pc_mg_distinct_smoothup 1207 1208 Level: advanced 1209 1210 Notes: 1211 this does not set a value on the coarsest grid, since we assume that 1212 there is no separate smooth up on the coarsest grid. 1213 1214 .seealso: PCMGSetNumberSmooth() 1215 @*/ 1216 PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) 1217 { 1218 PC_MG *mg = (PC_MG*)pc->data; 1219 PC_MG_Levels **mglevels = mg->levels; 1220 PetscErrorCode ierr; 1221 PetscInt i,levels; 1222 KSP subksp; 1223 1224 PetscFunctionBegin; 1225 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1226 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling"); 1227 levels = mglevels[0]->levels; 1228 1229 for (i=1; i<levels; i++) { 1230 const char *prefix = NULL; 1231 /* make sure smoother up and down are different */ 1232 ierr = PCMGGetSmootherUp(pc,i,&subksp);CHKERRQ(ierr); 1233 ierr = KSPGetOptionsPrefix(mglevels[i]->smoothd,&prefix);CHKERRQ(ierr); 1234 ierr = KSPSetOptionsPrefix(subksp,prefix);CHKERRQ(ierr); 1235 ierr = KSPAppendOptionsPrefix(subksp,"up_");CHKERRQ(ierr); 1236 } 1237 PetscFunctionReturn(0); 1238 } 1239 1240 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1241 PetscErrorCode PCGetInterpolations_MG(PC pc,PetscInt *num_levels,Mat *interpolations[]) 1242 { 1243 PC_MG *mg = (PC_MG*)pc->data; 1244 PC_MG_Levels **mglevels = mg->levels; 1245 Mat *mat; 1246 PetscInt l; 1247 PetscErrorCode ierr; 1248 1249 PetscFunctionBegin; 1250 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1251 ierr = PetscMalloc1(mg->nlevels,&mat);CHKERRQ(ierr); 1252 for (l=1; l< mg->nlevels; l++) { 1253 mat[l-1] = mglevels[l]->interpolate; 1254 ierr = PetscObjectReference((PetscObject)mat[l-1]);CHKERRQ(ierr); 1255 } 1256 *num_levels = mg->nlevels; 1257 *interpolations = mat; 1258 PetscFunctionReturn(0); 1259 } 1260 1261 /* No new matrices are created, and the coarse operator matrices are the references to the original ones */ 1262 PetscErrorCode PCGetCoarseOperators_MG(PC pc,PetscInt *num_levels,Mat *coarseOperators[]) 1263 { 1264 PC_MG *mg = (PC_MG*)pc->data; 1265 PC_MG_Levels **mglevels = mg->levels; 1266 PetscInt l; 1267 Mat *mat; 1268 PetscErrorCode ierr; 1269 1270 PetscFunctionBegin; 1271 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1272 ierr = PetscMalloc1(mg->nlevels,&mat);CHKERRQ(ierr); 1273 for (l=0; l<mg->nlevels-1; l++) { 1274 ierr = KSPGetOperators(mglevels[l]->smoothd,NULL,&(mat[l]));CHKERRQ(ierr); 1275 ierr = PetscObjectReference((PetscObject)mat[l]);CHKERRQ(ierr); 1276 } 1277 *num_levels = mg->nlevels; 1278 *coarseOperators = mat; 1279 PetscFunctionReturn(0); 1280 } 1281 1282 /* ----------------------------------------------------------------------------------------*/ 1283 1284 /*MC 1285 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1286 information about the coarser grid matrices and restriction/interpolation operators. 1287 1288 Options Database Keys: 1289 + -pc_mg_levels <nlevels> - number of levels including finest 1290 . -pc_mg_cycle_type <v,w> - provide the cycle desired 1291 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1292 . -pc_mg_log - log information about time spent on each level of the solver 1293 . -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes) 1294 . -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1295 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1296 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1297 to the Socket viewer for reading from MATLAB. 1298 - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 1299 to the binary output file called binaryoutput 1300 1301 Notes: 1302 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 1303 1304 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1305 1306 When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This 1307 is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing 1308 (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the 1309 residual is computed at the end of each cycle. 1310 1311 Level: intermediate 1312 1313 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE 1314 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), 1315 PCMGSetDistinctSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 1316 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1317 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1318 M*/ 1319 1320 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1321 { 1322 PC_MG *mg; 1323 PetscErrorCode ierr; 1324 1325 PetscFunctionBegin; 1326 ierr = PetscNewLog(pc,&mg);CHKERRQ(ierr); 1327 pc->data = (void*)mg; 1328 mg->nlevels = -1; 1329 mg->am = PC_MG_MULTIPLICATIVE; 1330 mg->galerkin = PC_MG_GALERKIN_NONE; 1331 1332 pc->useAmat = PETSC_TRUE; 1333 1334 pc->ops->apply = PCApply_MG; 1335 pc->ops->setup = PCSetUp_MG; 1336 pc->ops->reset = PCReset_MG; 1337 pc->ops->destroy = PCDestroy_MG; 1338 pc->ops->setfromoptions = PCSetFromOptions_MG; 1339 pc->ops->view = PCView_MG; 1340 1341 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG);CHKERRQ(ierr); 1342 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",PCMGGetLevels_MG);CHKERRQ(ierr); 1343 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",PCMGSetLevels_MG);CHKERRQ(ierr); 1344 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",PCGetInterpolations_MG);CHKERRQ(ierr); 1345 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",PCGetCoarseOperators_MG);CHKERRQ(ierr); 1346 PetscFunctionReturn(0); 1347 } 1348