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