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