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 = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr); 237 ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr); 238 ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr); 239 ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr); 240 ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr); 241 ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr); 242 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, i ? mg->default_smoothd : 1);CHKERRQ(ierr); 243 ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr); 244 ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level);CHKERRQ(ierr); 245 246 /* do special stuff for coarse grid */ 247 if (!i && levels > 1) { 248 ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr); 249 250 /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 251 ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr); 252 ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr); 253 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 254 if (size > 1) { 255 ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr); 256 } else { 257 ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr); 258 } 259 ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 260 } else { 261 char tprefix[128]; 262 sprintf(tprefix,"mg_levels_%d_",(int)i); 263 ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);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 703 mglevels[i]->smoothd->dm->x = vecs[0]; 704 705 ierr = PetscFree(vecs);CHKERRQ(ierr); 706 } 707 ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr); 708 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 709 ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr); 710 ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr); 711 } 712 } 713 if (!mg->galerkin && pc->dm) { 714 for (i=n-2; i>=0; i--) { 715 DM dmfine,dmcoarse; 716 Mat Restrict,Inject; 717 Vec rscale; 718 ierr = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr); 719 ierr = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr); 720 ierr = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr); 721 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 722 Inject = NULL; /* Callback should create it if it needs Injection */ 723 ierr = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr); 724 } 725 } 726 727 if (!pc->setupcalled) { 728 for (i=0; i<n; i++) { 729 ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr); 730 } 731 for (i=1; i<n; i++) { 732 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 733 ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr); 734 } 735 } 736 /* insure that if either interpolation or restriction is set the other other one is set */ 737 for (i=1; i<n; i++) { 738 ierr = PCMGGetInterpolation(pc,i,NULL);CHKERRQ(ierr); 739 ierr = PCMGGetRestriction(pc,i,NULL);CHKERRQ(ierr); 740 } 741 for (i=0; i<n-1; i++) { 742 if (!mglevels[i]->b) { 743 Vec *vec; 744 ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 745 ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr); 746 ierr = VecDestroy(vec);CHKERRQ(ierr); 747 ierr = PetscFree(vec);CHKERRQ(ierr); 748 } 749 if (!mglevels[i]->r && i) { 750 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 751 ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr); 752 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 753 } 754 if (!mglevels[i]->x) { 755 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 756 ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr); 757 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 758 } 759 } 760 if (n != 1 && !mglevels[n-1]->r) { 761 /* PCMGSetR() on the finest level if user did not supply it */ 762 Vec *vec; 763 ierr = KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 764 ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr); 765 ierr = VecDestroy(vec);CHKERRQ(ierr); 766 ierr = PetscFree(vec);CHKERRQ(ierr); 767 } 768 } 769 770 if (pc->dm) { 771 /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 772 for (i=0; i<n-1; i++) { 773 if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 774 } 775 } 776 777 for (i=1; i<n; i++) { 778 if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1){ 779 /* if doing only down then initial guess is zero */ 780 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 781 } 782 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 783 ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr); 784 if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) { 785 pc->failedreason = PC_SUBPC_ERROR; 786 } 787 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 788 if (!mglevels[i]->residual) { 789 Mat mat; 790 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&mat);CHKERRQ(ierr); 791 ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr); 792 } 793 } 794 for (i=1; i<n; i++) { 795 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 796 Mat downmat,downpmat; 797 798 /* check if operators have been set for up, if not use down operators to set them */ 799 ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr); 800 if (!opsset) { 801 ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr); 802 ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr); 803 } 804 805 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr); 806 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 807 ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr); 808 if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PCSETUP_FAILED) { 809 pc->failedreason = PC_SUBPC_ERROR; 810 } 811 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 812 } 813 } 814 815 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 816 ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr); 817 if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) { 818 pc->failedreason = PC_SUBPC_ERROR; 819 } 820 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 821 822 /* 823 Dump the interpolation/restriction matrices plus the 824 Jacobian/stiffness on each level. This allows MATLAB users to 825 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 826 827 Only support one or the other at the same time. 828 */ 829 #if defined(PETSC_USE_SOCKET_VIEWER) 830 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr); 831 if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc)); 832 dump = PETSC_FALSE; 833 #endif 834 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr); 835 if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc)); 836 837 if (viewer) { 838 for (i=1; i<n; i++) { 839 ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr); 840 } 841 for (i=0; i<n; i++) { 842 ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr); 843 ierr = MatView(pc->mat,viewer);CHKERRQ(ierr); 844 } 845 } 846 PetscFunctionReturn(0); 847 } 848 849 /* -------------------------------------------------------------------------------------*/ 850 851 #undef __FUNCT__ 852 #define __FUNCT__ "PCMGGetLevels" 853 /*@ 854 PCMGGetLevels - Gets the number of levels to use with MG. 855 856 Not Collective 857 858 Input Parameter: 859 . pc - the preconditioner context 860 861 Output parameter: 862 . levels - the number of levels 863 864 Level: advanced 865 866 .keywords: MG, get, levels, multigrid 867 868 .seealso: PCMGSetLevels() 869 @*/ 870 PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels) 871 { 872 PC_MG *mg = (PC_MG*)pc->data; 873 874 PetscFunctionBegin; 875 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 876 PetscValidIntPointer(levels,2); 877 *levels = mg->nlevels; 878 PetscFunctionReturn(0); 879 } 880 881 #undef __FUNCT__ 882 #define __FUNCT__ "PCMGSetType" 883 /*@ 884 PCMGSetType - Determines the form of multigrid to use: 885 multiplicative, additive, full, or the Kaskade algorithm. 886 887 Logically Collective on PC 888 889 Input Parameters: 890 + pc - the preconditioner context 891 - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 892 PC_MG_FULL, PC_MG_KASKADE 893 894 Options Database Key: 895 . -pc_mg_type <form> - Sets <form>, one of multiplicative, 896 additive, full, kaskade 897 898 Level: advanced 899 900 .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid 901 902 .seealso: PCMGSetLevels() 903 @*/ 904 PetscErrorCode PCMGSetType(PC pc,PCMGType form) 905 { 906 PC_MG *mg = (PC_MG*)pc->data; 907 908 PetscFunctionBegin; 909 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 910 PetscValidLogicalCollectiveEnum(pc,form,2); 911 mg->am = form; 912 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 913 else pc->ops->applyrichardson = NULL; 914 PetscFunctionReturn(0); 915 } 916 917 #undef __FUNCT__ 918 #define __FUNCT__ "PCMGGetType" 919 /*@ 920 PCMGGetType - Determines the form of multigrid to use: 921 multiplicative, additive, full, or the Kaskade algorithm. 922 923 Logically Collective on PC 924 925 Input Parameter: 926 . pc - the preconditioner context 927 928 Output Parameter: 929 . type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE 930 931 932 Level: advanced 933 934 .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid 935 936 .seealso: PCMGSetLevels() 937 @*/ 938 PetscErrorCode PCMGGetType(PC pc,PCMGType *type) 939 { 940 PC_MG *mg = (PC_MG*)pc->data; 941 942 PetscFunctionBegin; 943 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 944 *type = mg->am; 945 PetscFunctionReturn(0); 946 } 947 948 #undef __FUNCT__ 949 #define __FUNCT__ "PCMGSetCycleType" 950 /*@ 951 PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 952 complicated cycling. 953 954 Logically Collective on PC 955 956 Input Parameters: 957 + pc - the multigrid context 958 - PC_MG_CYCLE_V or PC_MG_CYCLE_W 959 960 Options Database Key: 961 . -pc_mg_cycle_type <v,w> 962 963 Level: advanced 964 965 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 966 967 .seealso: PCMGSetCycleTypeOnLevel() 968 @*/ 969 PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n) 970 { 971 PC_MG *mg = (PC_MG*)pc->data; 972 PC_MG_Levels **mglevels = mg->levels; 973 PetscInt i,levels; 974 975 PetscFunctionBegin; 976 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 977 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 978 PetscValidLogicalCollectiveEnum(pc,n,2); 979 levels = mglevels[0]->levels; 980 981 for (i=0; i<levels; i++) mglevels[i]->cycles = n; 982 PetscFunctionReturn(0); 983 } 984 985 #undef __FUNCT__ 986 #define __FUNCT__ "PCMGMultiplicativeSetCycles" 987 /*@ 988 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 989 of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 990 991 Logically Collective on PC 992 993 Input Parameters: 994 + pc - the multigrid context 995 - n - number of cycles (default is 1) 996 997 Options Database Key: 998 . -pc_mg_multiplicative_cycles n 999 1000 Level: advanced 1001 1002 Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 1003 1004 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 1005 1006 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType() 1007 @*/ 1008 PetscErrorCode PCMGMultiplicativeSetCycles(PC pc,PetscInt n) 1009 { 1010 PC_MG *mg = (PC_MG*)pc->data; 1011 1012 PetscFunctionBegin; 1013 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1014 PetscValidLogicalCollectiveInt(pc,n,2); 1015 mg->cyclesperpcapply = n; 1016 PetscFunctionReturn(0); 1017 } 1018 1019 #undef __FUNCT__ 1020 #define __FUNCT__ "PCMGSetGalerkin_MG" 1021 PetscErrorCode PCMGSetGalerkin_MG(PC pc,PetscBool use) 1022 { 1023 PC_MG *mg = (PC_MG*)pc->data; 1024 1025 PetscFunctionBegin; 1026 mg->galerkin = use ? 1 : 0; 1027 PetscFunctionReturn(0); 1028 } 1029 1030 #undef __FUNCT__ 1031 #define __FUNCT__ "PCMGSetGalerkin" 1032 /*@ 1033 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 1034 finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i 1035 1036 Logically Collective on PC 1037 1038 Input Parameters: 1039 + pc - the multigrid context 1040 - use - PETSC_TRUE to use the Galerkin process to compute coarse-level operators 1041 1042 Options Database Key: 1043 . -pc_mg_galerkin <true,false> 1044 1045 Level: intermediate 1046 1047 Notes: Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not 1048 use the PCMG construction of the coarser grids. 1049 1050 .keywords: MG, set, Galerkin 1051 1052 .seealso: PCMGGetGalerkin() 1053 1054 @*/ 1055 PetscErrorCode PCMGSetGalerkin(PC pc,PetscBool use) 1056 { 1057 PetscErrorCode ierr; 1058 1059 PetscFunctionBegin; 1060 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1061 ierr = PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PetscBool),(pc,use));CHKERRQ(ierr); 1062 PetscFunctionReturn(0); 1063 } 1064 1065 #undef __FUNCT__ 1066 #define __FUNCT__ "PCMGGetGalerkin" 1067 /*@ 1068 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 1069 A_i-1 = r_i * A_i * p_i 1070 1071 Not Collective 1072 1073 Input Parameter: 1074 . pc - the multigrid context 1075 1076 Output Parameter: 1077 . galerkin - PETSC_TRUE or PETSC_FALSE 1078 1079 Options Database Key: 1080 . -pc_mg_galerkin 1081 1082 Level: intermediate 1083 1084 .keywords: MG, set, Galerkin 1085 1086 .seealso: PCMGSetGalerkin() 1087 1088 @*/ 1089 PetscErrorCode PCMGGetGalerkin(PC pc,PetscBool *galerkin) 1090 { 1091 PC_MG *mg = (PC_MG*)pc->data; 1092 1093 PetscFunctionBegin; 1094 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1095 *galerkin = (PetscBool)mg->galerkin; 1096 PetscFunctionReturn(0); 1097 } 1098 1099 #undef __FUNCT__ 1100 #define __FUNCT__ "PCMGSetNumberSmoothDown" 1101 /*@ 1102 PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to 1103 use on all levels. Use PCMGGetSmootherDown() to set different 1104 pre-smoothing steps on different levels. 1105 1106 Logically Collective on PC 1107 1108 Input Parameters: 1109 + mg - the multigrid context 1110 - n - the number of smoothing steps 1111 1112 Options Database Key: 1113 . -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps 1114 1115 Level: advanced 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 /* make sure smoother up and down are different */ 1136 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1137 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1138 1139 mg->default_smoothd = n; 1140 } 1141 PetscFunctionReturn(0); 1142 } 1143 1144 #undef __FUNCT__ 1145 #define __FUNCT__ "PCMGSetNumberSmoothUp" 1146 /*@ 1147 PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use 1148 on all levels. Use PCMGGetSmootherUp() to set different numbers of 1149 post-smoothing steps on different levels. 1150 1151 Logically Collective on PC 1152 1153 Input Parameters: 1154 + mg - the multigrid context 1155 - n - the number of smoothing steps 1156 1157 Options Database Key: 1158 . -pc_mg_smoothup <n> - Sets number of post-smoothing steps 1159 1160 Level: advanced 1161 1162 Note: this does not set a value on the coarsest grid, since we assume that 1163 there is no separate smooth up on the coarsest grid. 1164 1165 .keywords: MG, smooth, up, post-smoothing, steps, multigrid 1166 1167 .seealso: PCMGSetNumberSmoothDown() 1168 @*/ 1169 PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n) 1170 { 1171 PC_MG *mg = (PC_MG*)pc->data; 1172 PC_MG_Levels **mglevels = mg->levels; 1173 PetscErrorCode ierr; 1174 PetscInt i,levels; 1175 1176 PetscFunctionBegin; 1177 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1178 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1179 PetscValidLogicalCollectiveInt(pc,n,2); 1180 levels = mglevels[0]->levels; 1181 1182 for (i=1; i<levels; i++) { 1183 /* make sure smoother up and down are different */ 1184 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1185 ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1186 1187 mg->default_smoothu = n; 1188 } 1189 PetscFunctionReturn(0); 1190 } 1191 1192 /* ----------------------------------------------------------------------------------------*/ 1193 1194 /*MC 1195 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1196 information about the coarser grid matrices and restriction/interpolation operators. 1197 1198 Options Database Keys: 1199 + -pc_mg_levels <nlevels> - number of levels including finest 1200 . -pc_mg_cycle_type <v,w> - 1201 . -pc_mg_smoothup <n> - number of smoothing steps after interpolation 1202 . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator 1203 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1204 . -pc_mg_log - log information about time spent on each level of the solver 1205 . -pc_mg_galerkin - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1206 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1207 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1208 to the Socket viewer for reading from MATLAB. 1209 - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 1210 to the binary output file called binaryoutput 1211 1212 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 1213 1214 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1215 1216 Level: intermediate 1217 1218 Concepts: multigrid/multilevel 1219 1220 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE 1221 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(), 1222 PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 1223 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1224 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1225 M*/ 1226 1227 #undef __FUNCT__ 1228 #define __FUNCT__ "PCCreate_MG" 1229 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1230 { 1231 PC_MG *mg; 1232 PetscErrorCode ierr; 1233 1234 PetscFunctionBegin; 1235 ierr = PetscNewLog(pc,&mg);CHKERRQ(ierr); 1236 pc->data = (void*)mg; 1237 mg->nlevels = -1; 1238 mg->am = PC_MG_MULTIPLICATIVE; 1239 1240 pc->useAmat = PETSC_TRUE; 1241 1242 pc->ops->apply = PCApply_MG; 1243 pc->ops->setup = PCSetUp_MG; 1244 pc->ops->reset = PCReset_MG; 1245 pc->ops->destroy = PCDestroy_MG; 1246 pc->ops->setfromoptions = PCSetFromOptions_MG; 1247 pc->ops->view = PCView_MG; 1248 1249 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG);CHKERRQ(ierr); 1250 PetscFunctionReturn(0); 1251 } 1252