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