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