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