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