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,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 MatStructure uflag; 542 Vec tvec; 543 DM *dms; 544 PetscViewer viewer = 0; 545 546 PetscFunctionBegin; 547 /* FIX: Move this to PCSetFromOptions_MG? */ 548 if (mg->usedmfornumberoflevels) { 549 PetscInt levels; 550 ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr); 551 levels++; 552 if (levels > n) { /* the problem is now being solved on a finer grid */ 553 ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr); 554 n = levels; 555 ierr = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 556 mglevels = mg->levels; 557 } 558 } 559 ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr); 560 561 562 /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 563 /* so use those from global PC */ 564 /* Is this what we always want? What if user wants to keep old one? */ 565 ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr); 566 if (opsset) { 567 Mat mmat; 568 ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat,NULL);CHKERRQ(ierr); 569 if (mmat == pc->pmat) opsset = PETSC_FALSE; 570 } 571 572 if (!opsset) { 573 ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr); 574 if(use_amat){ 575 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); 576 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr); 577 } 578 else { 579 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); 580 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat,pc->flag);CHKERRQ(ierr); 581 } 582 } 583 584 /* Skipping this for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? */ 585 if (pc->dm && mg->galerkin != 2 && !pc->setupcalled) { 586 /* construct the interpolation from the DMs */ 587 Mat p; 588 Vec rscale; 589 ierr = PetscMalloc1(n,&dms);CHKERRQ(ierr); 590 dms[n-1] = pc->dm; 591 for (i=n-2; i>-1; i--) { 592 DMKSP kdm; 593 ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr); 594 ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr); 595 if (mg->galerkin) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);} 596 ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr); 597 /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 598 * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 599 kdm->ops->computerhs = NULL; 600 kdm->rhsctx = NULL; 601 if (!mglevels[i+1]->interpolate) { 602 ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr); 603 ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr); 604 if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);} 605 ierr = VecDestroy(&rscale);CHKERRQ(ierr); 606 ierr = MatDestroy(&p);CHKERRQ(ierr); 607 } 608 } 609 610 for (i=n-2; i>-1; i--) { 611 ierr = DMDestroy(&dms[i]);CHKERRQ(ierr); 612 } 613 ierr = PetscFree(dms);CHKERRQ(ierr); 614 } 615 616 if (pc->dm && !pc->setupcalled) { 617 /* finest smoother also gets DM but it is not active, independent of whether galerkin==2 */ 618 ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr); 619 ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr); 620 } 621 622 if (mg->galerkin == 1) { 623 Mat B; 624 /* currently only handle case where mat and pmat are the same on coarser levels */ 625 ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB,&uflag);CHKERRQ(ierr); 626 if (!pc->setupcalled) { 627 for (i=n-2; i>-1; i--) { 628 if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct || !mglevels[i+1]->restrct) { 629 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr); 630 } else { 631 ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr); 632 } 633 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);CHKERRQ(ierr); 634 if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);} 635 dB = B; 636 } 637 if (n > 1) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);} 638 } else { 639 for (i=n-2; i>-1; i--) { 640 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B,NULL);CHKERRQ(ierr); 641 if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct || !mglevels[i+1]->restrct) { 642 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 643 } else { 644 ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 645 } 646 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);CHKERRQ(ierr); 647 dB = B; 648 } 649 } 650 } else if (!mg->galerkin && pc->dm && pc->dm->x) { 651 /* need to restrict Jacobian location to coarser meshes for evaluation */ 652 for (i=n-2; i>-1; i--) { 653 Mat R; 654 Vec rscale; 655 if (!mglevels[i]->smoothd->dm->x) { 656 Vec *vecs; 657 ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr); 658 659 mglevels[i]->smoothd->dm->x = vecs[0]; 660 661 ierr = PetscFree(vecs);CHKERRQ(ierr); 662 } 663 ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr); 664 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 665 ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr); 666 ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr); 667 } 668 } 669 if (!mg->galerkin && pc->dm) { 670 for (i=n-2; i>=0; i--) { 671 DM dmfine,dmcoarse; 672 Mat Restrict,Inject; 673 Vec rscale; 674 ierr = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr); 675 ierr = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr); 676 ierr = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr); 677 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 678 Inject = NULL; /* Callback should create it if it needs Injection */ 679 ierr = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr); 680 } 681 } 682 683 if (!pc->setupcalled) { 684 for (i=0; i<n; i++) { 685 ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr); 686 } 687 for (i=1; i<n; i++) { 688 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 689 ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr); 690 } 691 } 692 for (i=1; i<n; i++) { 693 ierr = PCMGGetInterpolation(pc,i,&mglevels[i]->interpolate);CHKERRQ(ierr); 694 ierr = PCMGGetRestriction(pc,i,&mglevels[i]->restrct);CHKERRQ(ierr); 695 } 696 for (i=0; i<n-1; i++) { 697 if (!mglevels[i]->b) { 698 Vec *vec; 699 ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 700 ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr); 701 ierr = VecDestroy(vec);CHKERRQ(ierr); 702 ierr = PetscFree(vec);CHKERRQ(ierr); 703 } 704 if (!mglevels[i]->r && i) { 705 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 706 ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr); 707 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 708 } 709 if (!mglevels[i]->x) { 710 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 711 ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr); 712 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 713 } 714 } 715 if (n != 1 && !mglevels[n-1]->r) { 716 /* PCMGSetR() on the finest level if user did not supply it */ 717 Vec *vec; 718 ierr = KSPGetVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 719 ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr); 720 ierr = VecDestroy(vec);CHKERRQ(ierr); 721 ierr = PetscFree(vec);CHKERRQ(ierr); 722 } 723 } 724 725 if (pc->dm) { 726 /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 727 for (i=0; i<n-1; i++) { 728 if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 729 } 730 } 731 732 for (i=1; i<n; i++) { 733 if (mglevels[i]->smoothu == mglevels[i]->smoothd) { 734 /* if doing only down then initial guess is zero */ 735 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 736 } 737 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 738 ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr); 739 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 740 if (!mglevels[i]->residual) { 741 Mat mat; 742 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&mat,NULL);CHKERRQ(ierr); 743 ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr); 744 } 745 } 746 for (i=1; i<n; i++) { 747 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 748 Mat downmat,downpmat; 749 MatStructure matflag; 750 751 /* check if operators have been set for up, if not use down operators to set them */ 752 ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr); 753 if (!opsset) { 754 ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat,&matflag);CHKERRQ(ierr); 755 ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat,matflag);CHKERRQ(ierr); 756 } 757 758 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr); 759 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 760 ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr); 761 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 762 } 763 } 764 765 /* 766 If coarse solver is not direct method then DO NOT USE preonly 767 */ 768 ierr = PetscObjectTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr); 769 if (preonly) { 770 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr); 771 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr); 772 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr); 773 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCSVD,&svd);CHKERRQ(ierr); 774 if (!lu && !redundant && !cholesky && !svd) { 775 ierr = KSPSetType(mglevels[0]->smoothd,KSPGMRES);CHKERRQ(ierr); 776 } 777 } 778 779 if (!pc->setupcalled) { 780 ierr = KSPSetFromOptions(mglevels[0]->smoothd);CHKERRQ(ierr); 781 } 782 783 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 784 ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr); 785 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 786 787 /* 788 Dump the interpolation/restriction matrices plus the 789 Jacobian/stiffness on each level. This allows MATLAB users to 790 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 791 792 Only support one or the other at the same time. 793 */ 794 #if defined(PETSC_USE_SOCKET_VIEWER) 795 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr); 796 if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 797 dump = PETSC_FALSE; 798 #endif 799 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr); 800 if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 801 802 if (viewer) { 803 for (i=1; i<n; i++) { 804 ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr); 805 } 806 for (i=0; i<n; i++) { 807 ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr); 808 ierr = MatView(pc->mat,viewer);CHKERRQ(ierr); 809 } 810 } 811 PetscFunctionReturn(0); 812 } 813 814 /* -------------------------------------------------------------------------------------*/ 815 816 #undef __FUNCT__ 817 #define __FUNCT__ "PCMGGetLevels" 818 /*@ 819 PCMGGetLevels - Gets the number of levels to use with MG. 820 821 Not Collective 822 823 Input Parameter: 824 . pc - the preconditioner context 825 826 Output parameter: 827 . levels - the number of levels 828 829 Level: advanced 830 831 .keywords: MG, get, levels, multigrid 832 833 .seealso: PCMGSetLevels() 834 @*/ 835 PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels) 836 { 837 PC_MG *mg = (PC_MG*)pc->data; 838 839 PetscFunctionBegin; 840 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 841 PetscValidIntPointer(levels,2); 842 *levels = mg->nlevels; 843 PetscFunctionReturn(0); 844 } 845 846 #undef __FUNCT__ 847 #define __FUNCT__ "PCMGSetType" 848 /*@ 849 PCMGSetType - Determines the form of multigrid to use: 850 multiplicative, additive, full, or the Kaskade algorithm. 851 852 Logically Collective on PC 853 854 Input Parameters: 855 + pc - the preconditioner context 856 - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 857 PC_MG_FULL, PC_MG_KASKADE 858 859 Options Database Key: 860 . -pc_mg_type <form> - Sets <form>, one of multiplicative, 861 additive, full, kaskade 862 863 Level: advanced 864 865 .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid 866 867 .seealso: PCMGSetLevels() 868 @*/ 869 PetscErrorCode PCMGSetType(PC pc,PCMGType form) 870 { 871 PC_MG *mg = (PC_MG*)pc->data; 872 873 PetscFunctionBegin; 874 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 875 PetscValidLogicalCollectiveEnum(pc,form,2); 876 mg->am = form; 877 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 878 else pc->ops->applyrichardson = 0; 879 PetscFunctionReturn(0); 880 } 881 882 #undef __FUNCT__ 883 #define __FUNCT__ "PCMGSetCycleType" 884 /*@ 885 PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 886 complicated cycling. 887 888 Logically Collective on PC 889 890 Input Parameters: 891 + pc - the multigrid context 892 - PC_MG_CYCLE_V or PC_MG_CYCLE_W 893 894 Options Database Key: 895 $ -pc_mg_cycle_type v or w 896 897 Level: advanced 898 899 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 900 901 .seealso: PCMGSetCycleTypeOnLevel() 902 @*/ 903 PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n) 904 { 905 PC_MG *mg = (PC_MG*)pc->data; 906 PC_MG_Levels **mglevels = mg->levels; 907 PetscInt i,levels; 908 909 PetscFunctionBegin; 910 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 911 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 912 PetscValidLogicalCollectiveInt(pc,n,2); 913 levels = mglevels[0]->levels; 914 915 for (i=0; i<levels; i++) mglevels[i]->cycles = n; 916 PetscFunctionReturn(0); 917 } 918 919 #undef __FUNCT__ 920 #define __FUNCT__ "PCMGMultiplicativeSetCycles" 921 /*@ 922 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 923 of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 924 925 Logically Collective on PC 926 927 Input Parameters: 928 + pc - the multigrid context 929 - n - number of cycles (default is 1) 930 931 Options Database Key: 932 $ -pc_mg_multiplicative_cycles n 933 934 Level: advanced 935 936 Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 937 938 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 939 940 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType() 941 @*/ 942 PetscErrorCode PCMGMultiplicativeSetCycles(PC pc,PetscInt n) 943 { 944 PC_MG *mg = (PC_MG*)pc->data; 945 PC_MG_Levels **mglevels = mg->levels; 946 PetscInt i,levels; 947 948 PetscFunctionBegin; 949 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 950 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 951 PetscValidLogicalCollectiveInt(pc,n,2); 952 levels = mglevels[0]->levels; 953 954 for (i=0; i<levels; i++) mg->cyclesperpcapply = n; 955 PetscFunctionReturn(0); 956 } 957 958 #undef __FUNCT__ 959 #define __FUNCT__ "PCMGSetGalerkin" 960 /*@ 961 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 962 finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 963 964 Logically Collective on PC 965 966 Input Parameters: 967 + pc - the multigrid context 968 - use - PETSC_TRUE to use the Galerkin process to compute coarse-level operators 969 970 Options Database Key: 971 $ -pc_mg_galerkin 972 973 Level: intermediate 974 975 .keywords: MG, set, Galerkin 976 977 .seealso: PCMGGetGalerkin() 978 979 @*/ 980 PetscErrorCode PCMGSetGalerkin(PC pc,PetscBool use) 981 { 982 PC_MG *mg = (PC_MG*)pc->data; 983 984 PetscFunctionBegin; 985 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 986 mg->galerkin = use ? 1 : 0; 987 PetscFunctionReturn(0); 988 } 989 990 #undef __FUNCT__ 991 #define __FUNCT__ "PCMGGetGalerkin" 992 /*@ 993 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 994 A_i-1 = r_i * A_i * p_i 995 996 Not Collective 997 998 Input Parameter: 999 . pc - the multigrid context 1000 1001 Output Parameter: 1002 . gelerkin - PETSC_TRUE or PETSC_FALSE 1003 1004 Options Database Key: 1005 $ -pc_mg_galerkin 1006 1007 Level: intermediate 1008 1009 .keywords: MG, set, Galerkin 1010 1011 .seealso: PCMGSetGalerkin() 1012 1013 @*/ 1014 PetscErrorCode PCMGGetGalerkin(PC pc,PetscBool *galerkin) 1015 { 1016 PC_MG *mg = (PC_MG*)pc->data; 1017 1018 PetscFunctionBegin; 1019 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1020 *galerkin = (PetscBool)mg->galerkin; 1021 PetscFunctionReturn(0); 1022 } 1023 1024 #undef __FUNCT__ 1025 #define __FUNCT__ "PCMGSetNumberSmoothDown" 1026 /*@ 1027 PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to 1028 use on all levels. Use PCMGGetSmootherDown() to set different 1029 pre-smoothing steps on different levels. 1030 1031 Logically Collective on PC 1032 1033 Input Parameters: 1034 + mg - the multigrid context 1035 - n - the number of smoothing steps 1036 1037 Options Database Key: 1038 . -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps 1039 1040 Level: advanced 1041 1042 .keywords: MG, smooth, down, pre-smoothing, steps, multigrid 1043 1044 .seealso: PCMGSetNumberSmoothUp() 1045 @*/ 1046 PetscErrorCode PCMGSetNumberSmoothDown(PC pc,PetscInt n) 1047 { 1048 PC_MG *mg = (PC_MG*)pc->data; 1049 PC_MG_Levels **mglevels = mg->levels; 1050 PetscErrorCode ierr; 1051 PetscInt i,levels; 1052 1053 PetscFunctionBegin; 1054 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1055 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1056 PetscValidLogicalCollectiveInt(pc,n,2); 1057 levels = mglevels[0]->levels; 1058 1059 for (i=1; i<levels; i++) { 1060 /* make sure smoother up and down are different */ 1061 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1062 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1063 1064 mg->default_smoothd = n; 1065 } 1066 PetscFunctionReturn(0); 1067 } 1068 1069 #undef __FUNCT__ 1070 #define __FUNCT__ "PCMGSetNumberSmoothUp" 1071 /*@ 1072 PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use 1073 on all levels. Use PCMGGetSmootherUp() to set different numbers of 1074 post-smoothing steps on different levels. 1075 1076 Logically Collective on PC 1077 1078 Input Parameters: 1079 + mg - the multigrid context 1080 - n - the number of smoothing steps 1081 1082 Options Database Key: 1083 . -pc_mg_smoothup <n> - Sets number of post-smoothing steps 1084 1085 Level: advanced 1086 1087 Note: this does not set a value on the coarsest grid, since we assume that 1088 there is no separate smooth up on the coarsest grid. 1089 1090 .keywords: MG, smooth, up, post-smoothing, steps, multigrid 1091 1092 .seealso: PCMGSetNumberSmoothDown() 1093 @*/ 1094 PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n) 1095 { 1096 PC_MG *mg = (PC_MG*)pc->data; 1097 PC_MG_Levels **mglevels = mg->levels; 1098 PetscErrorCode ierr; 1099 PetscInt i,levels; 1100 1101 PetscFunctionBegin; 1102 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1103 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1104 PetscValidLogicalCollectiveInt(pc,n,2); 1105 levels = mglevels[0]->levels; 1106 1107 for (i=1; i<levels; i++) { 1108 /* make sure smoother up and down are different */ 1109 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1110 ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1111 1112 mg->default_smoothu = n; 1113 } 1114 PetscFunctionReturn(0); 1115 } 1116 1117 /* ----------------------------------------------------------------------------------------*/ 1118 1119 /*MC 1120 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1121 information about the coarser grid matrices and restriction/interpolation operators. 1122 1123 Options Database Keys: 1124 + -pc_mg_levels <nlevels> - number of levels including finest 1125 . -pc_mg_cycles v or w 1126 . -pc_mg_smoothup <n> - number of smoothing steps after interpolation 1127 . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator 1128 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1129 . -pc_mg_log - log information about time spent on each level of the solver 1130 . -pc_mg_monitor - print information on the multigrid convergence 1131 . -pc_mg_galerkin - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1132 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1133 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1134 to the Socket viewer for reading from MATLAB. 1135 - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 1136 to the binary output file called binaryoutput 1137 1138 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 1139 1140 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1141 1142 Level: intermediate 1143 1144 Concepts: multigrid/multilevel 1145 1146 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE 1147 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(), 1148 PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 1149 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1150 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1151 M*/ 1152 1153 #undef __FUNCT__ 1154 #define __FUNCT__ "PCCreate_MG" 1155 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1156 { 1157 PC_MG *mg; 1158 PetscErrorCode ierr; 1159 1160 PetscFunctionBegin; 1161 ierr = PetscNewLog(pc,&mg);CHKERRQ(ierr); 1162 pc->data = (void*)mg; 1163 mg->nlevels = -1; 1164 1165 pc->useAmat = PETSC_TRUE; 1166 1167 pc->ops->apply = PCApply_MG; 1168 pc->ops->setup = PCSetUp_MG; 1169 pc->ops->reset = PCReset_MG; 1170 pc->ops->destroy = PCDestroy_MG; 1171 pc->ops->setfromoptions = PCSetFromOptions_MG; 1172 pc->ops->view = PCView_MG; 1173 PetscFunctionReturn(0); 1174 } 1175