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