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 17 PetscFunctionBegin; 18 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 19 ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr); /* pre-smooth */ 20 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 21 if (mglevels->level) { /* not the coarsest grid */ 22 if (mglevels->eventresidual) {ierr = PetscLogEventBegin(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);} 23 ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr); 24 if (mglevels->eventresidual) {ierr = PetscLogEventEnd(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);} 25 26 /* if on finest level and have convergence criteria set */ 27 if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) { 28 PetscReal rnorm; 29 ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr); 30 if (rnorm <= mg->ttol) { 31 if (rnorm < mg->abstol) { 32 *reason = PCRICHARDSON_CONVERGED_ATOL; 33 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol);CHKERRQ(ierr); 34 } else { 35 *reason = PCRICHARDSON_CONVERGED_RTOL; 36 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n",(double)rnorm,(double)mg->ttol);CHKERRQ(ierr); 37 } 38 PetscFunctionReturn(0); 39 } 40 } 41 42 mgc = *(mglevelsin - 1); 43 if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 44 ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr); 45 if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 46 ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr); 47 while (cycles--) { 48 ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr); 49 } 50 if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 51 ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr); 52 if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 53 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 54 ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr); /* post smooth */ 55 if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 56 } 57 PetscFunctionReturn(0); 58 } 59 60 #undef __FUNCT__ 61 #define __FUNCT__ "PCApplyRichardson_MG" 62 static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason) 63 { 64 PC_MG *mg = (PC_MG*)pc->data; 65 PC_MG_Levels **mglevels = mg->levels; 66 PetscErrorCode ierr; 67 PetscInt levels = mglevels[0]->levels,i; 68 69 PetscFunctionBegin; 70 /* When the DM is supplying the matrix then it will not exist until here */ 71 for (i=0; i<levels; i++) { 72 if (!mglevels[i]->A) { 73 ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr); 74 ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr); 75 } 76 } 77 mglevels[levels-1]->b = b; 78 mglevels[levels-1]->x = x; 79 80 mg->rtol = rtol; 81 mg->abstol = abstol; 82 mg->dtol = dtol; 83 if (rtol) { 84 /* compute initial residual norm for relative convergence test */ 85 PetscReal rnorm; 86 if (zeroguess) { 87 ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr); 88 } else { 89 ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr); 90 ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr); 91 } 92 mg->ttol = PetscMax(rtol*rnorm,abstol); 93 } else if (abstol) mg->ttol = abstol; 94 else mg->ttol = 0.0; 95 96 /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 97 stop prematurely due to small residual */ 98 for (i=1; i<levels; i++) { 99 ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 100 if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 101 ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 102 } 103 } 104 105 *reason = (PCRichardsonConvergedReason)0; 106 for (i=0; i<its; i++) { 107 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr); 108 if (*reason) break; 109 } 110 if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 111 *outits = i; 112 PetscFunctionReturn(0); 113 } 114 115 #undef __FUNCT__ 116 #define __FUNCT__ "PCReset_MG" 117 PetscErrorCode PCReset_MG(PC pc) 118 { 119 PC_MG *mg = (PC_MG*)pc->data; 120 PC_MG_Levels **mglevels = mg->levels; 121 PetscErrorCode ierr; 122 PetscInt i,n; 123 124 PetscFunctionBegin; 125 if (mglevels) { 126 n = mglevels[0]->levels; 127 for (i=0; i<n-1; i++) { 128 ierr = VecDestroy(&mglevels[i+1]->r);CHKERRQ(ierr); 129 ierr = VecDestroy(&mglevels[i]->b);CHKERRQ(ierr); 130 ierr = VecDestroy(&mglevels[i]->x);CHKERRQ(ierr); 131 ierr = MatDestroy(&mglevels[i+1]->restrct);CHKERRQ(ierr); 132 ierr = MatDestroy(&mglevels[i+1]->interpolate);CHKERRQ(ierr); 133 ierr = VecDestroy(&mglevels[i+1]->rscale);CHKERRQ(ierr); 134 } 135 136 for (i=0; i<n; i++) { 137 ierr = MatDestroy(&mglevels[i]->A);CHKERRQ(ierr); 138 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 139 ierr = KSPReset(mglevels[i]->smoothd);CHKERRQ(ierr); 140 } 141 ierr = KSPReset(mglevels[i]->smoothu);CHKERRQ(ierr); 142 } 143 } 144 PetscFunctionReturn(0); 145 } 146 147 #undef __FUNCT__ 148 #define __FUNCT__ "PCMGSetLevels" 149 /*@C 150 PCMGSetLevels - Sets the number of levels to use with MG. 151 Must be called before any other MG routine. 152 153 Logically Collective on PC 154 155 Input Parameters: 156 + pc - the preconditioner context 157 . levels - the number of levels 158 - comms - optional communicators for each level; this is to allow solving the coarser problems 159 on smaller sets of processors. Use NULL_OBJECT for default in Fortran 160 161 Level: intermediate 162 163 Notes: 164 If the number of levels is one then the multigrid uses the -mg_levels prefix 165 for setting the level options rather than the -mg_coarse prefix. 166 167 .keywords: MG, set, levels, multigrid 168 169 .seealso: PCMGSetType(), PCMGGetLevels() 170 @*/ 171 PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms) 172 { 173 PetscErrorCode ierr; 174 PC_MG *mg = (PC_MG*)pc->data; 175 MPI_Comm comm; 176 PC_MG_Levels **mglevels = mg->levels; 177 PetscInt i; 178 PetscMPIInt size; 179 const char *prefix; 180 PC ipc; 181 PetscInt n; 182 183 PetscFunctionBegin; 184 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 185 PetscValidLogicalCollectiveInt(pc,levels,2); 186 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 187 if (mg->nlevels == levels) PetscFunctionReturn(0); 188 if (mglevels) { 189 /* changing the number of levels so free up the previous stuff */ 190 ierr = PCReset_MG(pc);CHKERRQ(ierr); 191 n = mglevels[0]->levels; 192 for (i=0; i<n; i++) { 193 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 194 ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr); 195 } 196 ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr); 197 ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); 198 } 199 ierr = PetscFree(mg->levels);CHKERRQ(ierr); 200 } 201 202 mg->nlevels = levels; 203 204 ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr); 205 ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr); 206 207 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 208 209 mg->stageApply = 0; 210 for (i=0; i<levels; i++) { 211 ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr); 212 213 mglevels[i]->level = i; 214 mglevels[i]->levels = levels; 215 mglevels[i]->cycles = PC_MG_CYCLE_V; 216 mg->default_smoothu = 2; 217 mg->default_smoothd = 2; 218 mglevels[i]->eventsmoothsetup = 0; 219 mglevels[i]->eventsmoothsolve = 0; 220 mglevels[i]->eventresidual = 0; 221 mglevels[i]->eventinterprestrict = 0; 222 223 if (comms) comm = comms[i]; 224 ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr); 225 ierr = KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure);CHKERRQ(ierr); 226 ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr); 227 ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr); 228 ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr); 229 ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr); 230 ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr); 231 ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr); 232 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, i ? mg->default_smoothd : 1);CHKERRQ(ierr); 233 ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr); 234 235 /* do special stuff for coarse grid */ 236 if (!i && levels > 1) { 237 ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr); 238 239 /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ 240 ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr); 241 ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr); 242 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 243 if (size > 1) { 244 KSP innerksp; 245 PC innerpc; 246 ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr); 247 ierr = PCRedundantGetKSP(ipc,&innerksp);CHKERRQ(ierr); 248 ierr = KSPGetPC(innerksp,&innerpc);CHKERRQ(ierr); 249 ierr = PCFactorSetShiftType(innerpc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 250 } else { 251 ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr); 252 ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 253 } 254 } else { 255 char tprefix[128]; 256 sprintf(tprefix,"mg_levels_%d_",(int)i); 257 ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr); 258 } 259 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr); 260 261 mglevels[i]->smoothu = mglevels[i]->smoothd; 262 mg->rtol = 0.0; 263 mg->abstol = 0.0; 264 mg->dtol = 0.0; 265 mg->ttol = 0.0; 266 mg->cyclesperpcapply = 1; 267 } 268 mg->am = PC_MG_MULTIPLICATIVE; 269 mg->levels = mglevels; 270 pc->ops->applyrichardson = PCApplyRichardson_MG; 271 PetscFunctionReturn(0); 272 } 273 274 275 #undef __FUNCT__ 276 #define __FUNCT__ "PCDestroy_MG" 277 PetscErrorCode PCDestroy_MG(PC pc) 278 { 279 PetscErrorCode ierr; 280 PC_MG *mg = (PC_MG*)pc->data; 281 PC_MG_Levels **mglevels = mg->levels; 282 PetscInt i,n; 283 284 PetscFunctionBegin; 285 ierr = PCReset_MG(pc);CHKERRQ(ierr); 286 if (mglevels) { 287 n = mglevels[0]->levels; 288 for (i=0; i<n; i++) { 289 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 290 ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr); 291 } 292 ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr); 293 ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); 294 } 295 ierr = PetscFree(mg->levels);CHKERRQ(ierr); 296 } 297 ierr = PetscFree(pc->data);CHKERRQ(ierr); 298 PetscFunctionReturn(0); 299 } 300 301 302 303 extern PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**); 304 extern PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**); 305 extern PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**); 306 307 /* 308 PCApply_MG - Runs either an additive, multiplicative, Kaskadic 309 or full cycle of multigrid. 310 311 Note: 312 A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 313 */ 314 #undef __FUNCT__ 315 #define __FUNCT__ "PCApply_MG" 316 static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x) 317 { 318 PC_MG *mg = (PC_MG*)pc->data; 319 PC_MG_Levels **mglevels = mg->levels; 320 PetscErrorCode ierr; 321 PetscInt levels = mglevels[0]->levels,i; 322 323 PetscFunctionBegin; 324 if (mg->stageApply) {ierr = PetscLogStagePush(mg->stageApply);CHKERRQ(ierr);} 325 /* When the DM is supplying the matrix then it will not exist until here */ 326 for (i=0; i<levels; i++) { 327 if (!mglevels[i]->A) { 328 ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr); 329 ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr); 330 } 331 } 332 333 mglevels[levels-1]->b = b; 334 mglevels[levels-1]->x = x; 335 if (mg->am == PC_MG_MULTIPLICATIVE) { 336 ierr = VecSet(x,0.0);CHKERRQ(ierr); 337 for (i=0; i<mg->cyclesperpcapply; i++) { 338 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,NULL);CHKERRQ(ierr); 339 } 340 } else if (mg->am == PC_MG_ADDITIVE) { 341 ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr); 342 } else if (mg->am == PC_MG_KASKADE) { 343 ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr); 344 } else { 345 ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr); 346 } 347 if (mg->stageApply) {ierr = PetscLogStagePop();CHKERRQ(ierr);} 348 PetscFunctionReturn(0); 349 } 350 351 352 #undef __FUNCT__ 353 #define __FUNCT__ "PCSetFromOptions_MG" 354 PetscErrorCode PCSetFromOptions_MG(PetscOptions *PetscOptionsObject,PC pc) 355 { 356 PetscErrorCode ierr; 357 PetscInt m,levels = 1,cycles; 358 PetscBool flg,set; 359 PC_MG *mg = (PC_MG*)pc->data; 360 PC_MG_Levels **mglevels = mg->levels; 361 PCMGType mgtype; 362 PCMGCycleType mgctype; 363 364 PetscFunctionBegin; 365 ierr = PetscOptionsHead(PetscOptionsObject,"Multigrid options");CHKERRQ(ierr); 366 if (!mg->levels) { 367 ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr); 368 if (!flg && pc->dm) { 369 ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr); 370 levels++; 371 mg->usedmfornumberoflevels = PETSC_TRUE; 372 } 373 ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr); 374 } 375 mglevels = mg->levels; 376 377 mgctype = (PCMGCycleType) mglevels[0]->cycles; 378 ierr = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr); 379 if (flg) { 380 ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr); 381 } 382 flg = PETSC_FALSE; 383 ierr = PetscOptionsBool("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",flg,&flg,&set);CHKERRQ(ierr); 384 if (set) { 385 ierr = PCMGSetGalerkin(pc,flg);CHKERRQ(ierr); 386 } 387 ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",mg->default_smoothu,&m,&flg);CHKERRQ(ierr); 388 if (flg) { 389 ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr); 390 } 391 ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",mg->default_smoothd,&m,&flg);CHKERRQ(ierr); 392 if (flg) { 393 ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr); 394 } 395 mgtype = mg->am; 396 ierr = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr); 397 if (flg) { 398 ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr); 399 } 400 if (mg->am == PC_MG_MULTIPLICATIVE) { 401 ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr); 402 if (flg) { 403 ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr); 404 } 405 } 406 flg = PETSC_FALSE; 407 ierr = PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL);CHKERRQ(ierr); 408 if (flg) { 409 PetscInt i; 410 char eventname[128]; 411 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 412 levels = mglevels[0]->levels; 413 for (i=0; i<levels; i++) { 414 sprintf(eventname,"MGSetup Level %d",(int)i); 415 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup);CHKERRQ(ierr); 416 sprintf(eventname,"MGSmooth Level %d",(int)i); 417 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve);CHKERRQ(ierr); 418 if (i) { 419 sprintf(eventname,"MGResid Level %d",(int)i); 420 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual);CHKERRQ(ierr); 421 sprintf(eventname,"MGInterp Level %d",(int)i); 422 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict);CHKERRQ(ierr); 423 } 424 } 425 426 #if defined(PETSC_USE_LOG) 427 { 428 const char *sname = "MG Apply"; 429 PetscStageLog stageLog; 430 PetscInt st; 431 432 PetscFunctionBegin; 433 ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr); 434 for (st = 0; st < stageLog->numStages; ++st) { 435 PetscBool same; 436 437 ierr = PetscStrcmp(stageLog->stageInfo[st].name, sname, &same);CHKERRQ(ierr); 438 if (same) mg->stageApply = st; 439 } 440 if (!mg->stageApply) { 441 ierr = PetscLogStageRegister(sname, &mg->stageApply);CHKERRQ(ierr); 442 } 443 } 444 #endif 445 } 446 ierr = PetscOptionsTail();CHKERRQ(ierr); 447 PetscFunctionReturn(0); 448 } 449 450 const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0}; 451 const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0}; 452 453 #include <petscdraw.h> 454 #undef __FUNCT__ 455 #define __FUNCT__ "PCView_MG" 456 PetscErrorCode PCView_MG(PC pc,PetscViewer viewer) 457 { 458 PC_MG *mg = (PC_MG*)pc->data; 459 PC_MG_Levels **mglevels = mg->levels; 460 PetscErrorCode ierr; 461 PetscInt levels = mglevels ? mglevels[0]->levels : 0,i; 462 PetscBool iascii,isbinary,isdraw; 463 464 PetscFunctionBegin; 465 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 466 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr); 467 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 468 if (iascii) { 469 const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown"; 470 ierr = PetscViewerASCIIPrintf(viewer," MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename);CHKERRQ(ierr); 471 if (mg->am == PC_MG_MULTIPLICATIVE) { 472 ierr = PetscViewerASCIIPrintf(viewer," Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr); 473 } 474 if (mg->galerkin) { 475 ierr = PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 476 } else { 477 ierr = PetscViewerASCIIPrintf(viewer," Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 478 } 479 if (mg->view){ 480 ierr = (*mg->view)(pc,viewer);CHKERRQ(ierr); 481 } 482 for (i=0; i<levels; i++) { 483 if (!i) { 484 ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i);CHKERRQ(ierr); 485 } else { 486 ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr); 487 } 488 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 489 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 490 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 491 if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 492 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr); 493 } else if (i) { 494 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr); 495 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 496 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 497 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 498 } 499 } 500 } else if (isbinary) { 501 for (i=levels-1; i>=0; i--) { 502 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 503 if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) { 504 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 505 } 506 } 507 } else if (isdraw) { 508 PetscDraw draw; 509 PetscReal x,w,y,bottom,th; 510 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 511 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 512 ierr = PetscDrawStringGetSize(draw,NULL,&th);CHKERRQ(ierr); 513 bottom = y - th; 514 for (i=levels-1; i>=0; i--) { 515 if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) { 516 ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr); 517 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 518 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 519 } else { 520 w = 0.5*PetscMin(1.0-x,x); 521 ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr); 522 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 523 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 524 ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr); 525 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 526 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 527 } 528 ierr = PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL);CHKERRQ(ierr); 529 bottom -= th; 530 } 531 } 532 PetscFunctionReturn(0); 533 } 534 535 #include <petsc/private/dmimpl.h> 536 #include <petsc/private/kspimpl.h> 537 538 /* 539 Calls setup for the KSP on each level 540 */ 541 #undef __FUNCT__ 542 #define __FUNCT__ "PCSetUp_MG" 543 PetscErrorCode PCSetUp_MG(PC pc) 544 { 545 PC_MG *mg = (PC_MG*)pc->data; 546 PC_MG_Levels **mglevels = mg->levels; 547 PetscErrorCode ierr; 548 PetscInt i,n = mglevels[0]->levels; 549 PC cpc; 550 PetscBool preonly,lu,redundant,cholesky,svd,dump = PETSC_FALSE,opsset,use_amat,missinginterpolate = PETSC_FALSE,bjaclu; 551 Mat dA,dB; 552 Vec tvec; 553 DM *dms; 554 PetscViewer viewer = 0; 555 556 PetscFunctionBegin; 557 /* FIX: Move this to PCSetFromOptions_MG? */ 558 if (mg->usedmfornumberoflevels) { 559 PetscInt levels; 560 ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr); 561 levels++; 562 if (levels > n) { /* the problem is now being solved on a finer grid */ 563 ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr); 564 n = levels; 565 ierr = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */ 566 mglevels = mg->levels; 567 } 568 } 569 ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr); 570 571 572 /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 573 /* so use those from global PC */ 574 /* Is this what we always want? What if user wants to keep old one? */ 575 ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr); 576 if (opsset) { 577 Mat mmat; 578 ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat);CHKERRQ(ierr); 579 if (mmat == pc->pmat) opsset = PETSC_FALSE; 580 } 581 582 if (!opsset) { 583 ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr); 584 if(use_amat){ 585 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); 586 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat);CHKERRQ(ierr); 587 } 588 else { 589 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); 590 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat);CHKERRQ(ierr); 591 } 592 } 593 594 for (i=n-1; i>0; i--) { 595 if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) { 596 missinginterpolate = PETSC_TRUE; 597 continue; 598 } 599 } 600 /* 601 Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS) 602 Skipping for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? 603 */ 604 if (missinginterpolate && pc->dm && mg->galerkin != 2 && !pc->setupcalled) { 605 /* construct the interpolation from the DMs */ 606 Mat p; 607 Vec rscale; 608 ierr = PetscMalloc1(n,&dms);CHKERRQ(ierr); 609 dms[n-1] = pc->dm; 610 /* Separately create them so we do not get DMKSP interference between levels */ 611 for (i=n-2; i>-1; i--) {ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr);} 612 for (i=n-2; i>-1; i--) { 613 DMKSP kdm; 614 ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr); 615 if (mg->galerkin) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);} 616 ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr); 617 /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take 618 * a bitwise OR of computing the matrix, RHS, and initial iterate. */ 619 kdm->ops->computerhs = NULL; 620 kdm->rhsctx = NULL; 621 if (!mglevels[i+1]->interpolate) { 622 ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr); 623 ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr); 624 if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);} 625 ierr = VecDestroy(&rscale);CHKERRQ(ierr); 626 ierr = MatDestroy(&p);CHKERRQ(ierr); 627 } 628 } 629 630 for (i=n-2; i>-1; i--) {ierr = DMDestroy(&dms[i]);CHKERRQ(ierr);} 631 ierr = PetscFree(dms);CHKERRQ(ierr); 632 } 633 634 if (pc->dm && !pc->setupcalled) { 635 /* finest smoother also gets DM but it is not active, independent of whether galerkin==2 */ 636 ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr); 637 ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr); 638 } 639 640 if (mg->galerkin == 1) { 641 Mat B; 642 /* currently only handle case where mat and pmat are the same on coarser levels */ 643 ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB);CHKERRQ(ierr); 644 if (!pc->setupcalled) { 645 for (i=n-2; i>-1; i--) { 646 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"); 647 if (!mglevels[i+1]->interpolate) { 648 ierr = PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct);CHKERRQ(ierr); 649 } 650 if (!mglevels[i+1]->restrct) { 651 ierr = PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate);CHKERRQ(ierr); 652 } 653 if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct) { 654 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr); 655 } else { 656 ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr); 657 } 658 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B);CHKERRQ(ierr); 659 if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);} 660 dB = B; 661 } 662 if (n > 1) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);} 663 } else { 664 for (i=n-2; i>-1; i--) { 665 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"); 666 if (!mglevels[i+1]->interpolate) { 667 ierr = PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct);CHKERRQ(ierr); 668 } 669 if (!mglevels[i+1]->restrct) { 670 ierr = PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate);CHKERRQ(ierr); 671 } 672 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B);CHKERRQ(ierr); 673 if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct) { 674 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 675 } else { 676 ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 677 } 678 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B);CHKERRQ(ierr); 679 dB = B; 680 } 681 } 682 } else if (!mg->galerkin && pc->dm && pc->dm->x) { 683 /* need to restrict Jacobian location to coarser meshes for evaluation */ 684 for (i=n-2; i>-1; i--) { 685 Mat R; 686 Vec rscale; 687 if (!mglevels[i]->smoothd->dm->x) { 688 Vec *vecs; 689 ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr); 690 691 mglevels[i]->smoothd->dm->x = vecs[0]; 692 693 ierr = PetscFree(vecs);CHKERRQ(ierr); 694 } 695 ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr); 696 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 697 ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr); 698 ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr); 699 } 700 } 701 if (!mg->galerkin && pc->dm) { 702 for (i=n-2; i>=0; i--) { 703 DM dmfine,dmcoarse; 704 Mat Restrict,Inject; 705 Vec rscale; 706 ierr = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr); 707 ierr = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr); 708 ierr = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr); 709 ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr); 710 Inject = NULL; /* Callback should create it if it needs Injection */ 711 ierr = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr); 712 } 713 } 714 715 if (!pc->setupcalled) { 716 for (i=0; i<n; i++) { 717 ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr); 718 } 719 for (i=1; i<n; i++) { 720 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 721 ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr); 722 } 723 } 724 for (i=1; i<n; i++) { 725 ierr = PCMGGetInterpolation(pc,i,&mglevels[i]->interpolate);CHKERRQ(ierr); 726 ierr = PCMGGetRestriction(pc,i,&mglevels[i]->restrct);CHKERRQ(ierr); 727 } 728 for (i=0; i<n-1; i++) { 729 if (!mglevels[i]->b) { 730 Vec *vec; 731 ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 732 ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr); 733 ierr = VecDestroy(vec);CHKERRQ(ierr); 734 ierr = PetscFree(vec);CHKERRQ(ierr); 735 } 736 if (!mglevels[i]->r && i) { 737 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 738 ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr); 739 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 740 } 741 if (!mglevels[i]->x) { 742 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 743 ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr); 744 ierr = VecDestroy(&tvec);CHKERRQ(ierr); 745 } 746 } 747 if (n != 1 && !mglevels[n-1]->r) { 748 /* PCMGSetR() on the finest level if user did not supply it */ 749 Vec *vec; 750 ierr = KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr); 751 ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr); 752 ierr = VecDestroy(vec);CHKERRQ(ierr); 753 ierr = PetscFree(vec);CHKERRQ(ierr); 754 } 755 } 756 757 if (pc->dm) { 758 /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */ 759 for (i=0; i<n-1; i++) { 760 if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX; 761 } 762 } 763 764 for (i=1; i<n; i++) { 765 if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1){ 766 /* if doing only down then initial guess is zero */ 767 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 768 } 769 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 770 ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr); 771 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 772 if (!mglevels[i]->residual) { 773 Mat mat; 774 ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&mat);CHKERRQ(ierr); 775 ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr); 776 } 777 } 778 for (i=1; i<n; i++) { 779 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 780 Mat downmat,downpmat; 781 782 /* check if operators have been set for up, if not use down operators to set them */ 783 ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr); 784 if (!opsset) { 785 ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr); 786 ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr); 787 } 788 789 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr); 790 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 791 ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr); 792 if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 793 } 794 } 795 796 /* 797 If coarse solver is not direct method then DO NOT USE preonly 798 */ 799 ierr = PetscObjectTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr); 800 if (preonly) { 801 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCBJACOBI,&bjaclu);CHKERRQ(ierr); 802 if (bjaclu) { 803 KSP *k2; PetscInt ii,first; PC pc2; 804 ierr = PCBJacobiGetSubKSP(cpc,&ii,&first,&k2);CHKERRQ(ierr); 805 if (ii != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"ii %D is not one",ii); 806 ierr = KSPGetPC(k2[0],&pc2);CHKERRQ(ierr); 807 ierr = PetscObjectTypeCompare((PetscObject)pc2,PCLU,&bjaclu);CHKERRQ(ierr); 808 } 809 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr); 810 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr); 811 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr); 812 ierr = PetscObjectTypeCompare((PetscObject)cpc,PCSVD,&svd);CHKERRQ(ierr); 813 if (!lu && !redundant && !cholesky && !svd && !bjaclu) { 814 ierr = KSPSetType(mglevels[0]->smoothd,KSPGMRES);CHKERRQ(ierr); 815 } 816 } 817 818 if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 819 ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr); 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)->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)->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 /*@ 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 PetscValidLogicalCollectiveInt(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 1115 .keywords: MG, smooth, down, pre-smoothing, steps, multigrid 1116 1117 .seealso: PCMGSetNumberSmoothUp() 1118 @*/ 1119 PetscErrorCode PCMGSetNumberSmoothDown(PC pc,PetscInt n) 1120 { 1121 PC_MG *mg = (PC_MG*)pc->data; 1122 PC_MG_Levels **mglevels = mg->levels; 1123 PetscErrorCode ierr; 1124 PetscInt i,levels; 1125 1126 PetscFunctionBegin; 1127 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1128 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1129 PetscValidLogicalCollectiveInt(pc,n,2); 1130 levels = mglevels[0]->levels; 1131 1132 for (i=1; i<levels; i++) { 1133 /* make sure smoother up and down are different */ 1134 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1135 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1136 1137 mg->default_smoothd = n; 1138 } 1139 PetscFunctionReturn(0); 1140 } 1141 1142 #undef __FUNCT__ 1143 #define __FUNCT__ "PCMGSetNumberSmoothUp" 1144 /*@ 1145 PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use 1146 on all levels. Use PCMGGetSmootherUp() to set different numbers of 1147 post-smoothing steps on different levels. 1148 1149 Logically Collective on PC 1150 1151 Input Parameters: 1152 + mg - the multigrid context 1153 - n - the number of smoothing steps 1154 1155 Options Database Key: 1156 . -pc_mg_smoothup <n> - Sets number of post-smoothing steps 1157 1158 Level: advanced 1159 1160 Note: this does not set a value on the coarsest grid, since we assume that 1161 there is no separate smooth up on the coarsest grid. 1162 1163 .keywords: MG, smooth, up, post-smoothing, steps, multigrid 1164 1165 .seealso: PCMGSetNumberSmoothDown() 1166 @*/ 1167 PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n) 1168 { 1169 PC_MG *mg = (PC_MG*)pc->data; 1170 PC_MG_Levels **mglevels = mg->levels; 1171 PetscErrorCode ierr; 1172 PetscInt i,levels; 1173 1174 PetscFunctionBegin; 1175 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1176 if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 1177 PetscValidLogicalCollectiveInt(pc,n,2); 1178 levels = mglevels[0]->levels; 1179 1180 for (i=1; i<levels; i++) { 1181 /* make sure smoother up and down are different */ 1182 ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); 1183 ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 1184 1185 mg->default_smoothu = n; 1186 } 1187 PetscFunctionReturn(0); 1188 } 1189 1190 /* ----------------------------------------------------------------------------------------*/ 1191 1192 /*MC 1193 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 1194 information about the coarser grid matrices and restriction/interpolation operators. 1195 1196 Options Database Keys: 1197 + -pc_mg_levels <nlevels> - number of levels including finest 1198 . -pc_mg_cycles <v,w> - 1199 . -pc_mg_smoothup <n> - number of smoothing steps after interpolation 1200 . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator 1201 . -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default 1202 . -pc_mg_log - log information about time spent on each level of the solver 1203 . -pc_mg_galerkin - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R' 1204 . -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1) 1205 . -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 1206 to the Socket viewer for reading from MATLAB. 1207 - -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices 1208 to the binary output file called binaryoutput 1209 1210 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 1211 1212 When run with a single level the smoother options are used on that level NOT the coarse grid solver options 1213 1214 Level: intermediate 1215 1216 Concepts: multigrid/multilevel 1217 1218 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE 1219 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(), 1220 PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 1221 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1222 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1223 M*/ 1224 1225 #undef __FUNCT__ 1226 #define __FUNCT__ "PCCreate_MG" 1227 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) 1228 { 1229 PC_MG *mg; 1230 PetscErrorCode ierr; 1231 1232 PetscFunctionBegin; 1233 ierr = PetscNewLog(pc,&mg);CHKERRQ(ierr); 1234 pc->data = (void*)mg; 1235 mg->nlevels = -1; 1236 1237 pc->useAmat = PETSC_TRUE; 1238 1239 pc->ops->apply = PCApply_MG; 1240 pc->ops->setup = PCSetUp_MG; 1241 pc->ops->reset = PCReset_MG; 1242 pc->ops->destroy = PCDestroy_MG; 1243 pc->ops->setfromoptions = PCSetFromOptions_MG; 1244 pc->ops->view = PCView_MG; 1245 1246 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG);CHKERRQ(ierr); 1247 PetscFunctionReturn(0); 1248 } 1249