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