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