1 #define PETSCKSP_DLL 2 3 /* 4 Defines the multigrid preconditioner interface. 5 */ 6 #include "../src/ksp/pc/impls/mg/mgimpl.h" /*I "petscmg.h" I*/ 7 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "PCMGMCycle_Private" 11 PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PCRichardsonConvergedReason *reason) 12 { 13 PC_MG *mg = (PC_MG*)pc->data; 14 PC_MG_Levels *mgc,*mglevels = *mglevelsin; 15 PetscErrorCode ierr; 16 PetscInt cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles; 17 18 PetscFunctionBegin; 19 20 if (mg->eventsmoothsolve) {ierr = PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 21 ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr); /* pre-smooth */ 22 if (mg->eventsmoothsolve) {ierr = PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 23 if (mglevels->level) { /* not the coarsest grid */ 24 if (mg->eventresidual) {ierr = PetscLogEventBegin(mg->eventresidual,0,0,0,0);CHKERRQ(ierr);} 25 ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr); 26 if (mg->eventresidual) {ierr = PetscLogEventEnd(mg->eventresidual,0,0,0,0);CHKERRQ(ierr);} 27 28 /* if on finest level and have convergence criteria set */ 29 if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) { 30 PetscReal rnorm; 31 ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr); 32 if (rnorm <= mg->ttol) { 33 if (rnorm < mg->abstol) { 34 *reason = PCRICHARDSON_CONVERGED_ATOL; 35 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);CHKERRQ(ierr); 36 } else { 37 *reason = PCRICHARDSON_CONVERGED_RTOL; 38 ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);CHKERRQ(ierr); 39 } 40 PetscFunctionReturn(0); 41 } 42 } 43 44 mgc = *(mglevelsin - 1); 45 if (mg->eventinterprestrict) {ierr = PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 46 ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr); 47 if (mg->eventinterprestrict) {ierr = PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 48 ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr); 49 while (cycles--) { 50 ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr); 51 } 52 if (mg->eventinterprestrict) {ierr = PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 53 ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr); 54 if (mg->eventinterprestrict) {ierr = PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);} 55 if (mg->eventsmoothsolve) {ierr = PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 56 ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr); /* post smooth */ 57 if (mg->eventsmoothsolve) {ierr = PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);} 58 } 59 PetscFunctionReturn(0); 60 } 61 62 #undef __FUNCT__ 63 #define __FUNCT__ "PCApplyRichardson_MG" 64 static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscTruth zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason) 65 { 66 PC_MG *mg = (PC_MG*)pc->data; 67 PC_MG_Levels **mglevels = mg->levels; 68 PetscErrorCode ierr; 69 PetscInt levels = mglevels[0]->levels,i; 70 71 PetscFunctionBegin; 72 mglevels[levels-1]->b = b; 73 mglevels[levels-1]->x = x; 74 75 mg->rtol = rtol; 76 mg->abstol = abstol; 77 mg->dtol = dtol; 78 if (rtol) { 79 /* compute initial residual norm for relative convergence test */ 80 PetscReal rnorm; 81 if (zeroguess) { 82 ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr); 83 } else { 84 ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr); 85 ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr); 86 } 87 mg->ttol = PetscMax(rtol*rnorm,abstol); 88 } else if (abstol) { 89 mg->ttol = abstol; 90 } else { 91 mg->ttol = 0.0; 92 } 93 94 /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 95 stop prematurely do to small residual */ 96 for (i=1; i<levels; i++) { 97 ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 98 if (mglevels[i]->smoothu != mglevels[i]->smoothd) { 99 ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 100 } 101 } 102 103 *reason = (PCRichardsonConvergedReason)0; 104 for (i=0; i<its; i++) { 105 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr); 106 if (*reason) break; 107 } 108 if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 109 *outits = i; 110 PetscFunctionReturn(0); 111 } 112 113 #undef __FUNCT__ 114 #define __FUNCT__ "PCMGSetLevels" 115 /*@C 116 PCMGSetLevels - Sets the number of levels to use with MG. 117 Must be called before any other MG routine. 118 119 Collective on PC 120 121 Input Parameters: 122 + pc - the preconditioner context 123 . levels - the number of levels 124 - comms - optional communicators for each level; this is to allow solving the coarser problems 125 on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran 126 127 Level: intermediate 128 129 Notes: 130 If the number of levels is one then the multigrid uses the -mg_levels prefix 131 for setting the level options rather than the -mg_coarse prefix. 132 133 .keywords: MG, set, levels, multigrid 134 135 .seealso: PCMGSetType(), PCMGGetLevels() 136 @*/ 137 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms) 138 { 139 PetscErrorCode ierr; 140 PC_MG *mg = (PC_MG*)pc->data; 141 MPI_Comm comm = ((PetscObject)pc)->comm; 142 PC_MG_Levels **mglevels; 143 PetscInt i; 144 PetscMPIInt size; 145 const char *prefix; 146 PC ipc; 147 148 PetscFunctionBegin; 149 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 150 if (mg->nlevels > -1) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ORDER,"Number levels already set for MG\n make sure that you call PCMGSetLevels() before KSPSetFromOptions()"); 151 if (mg->levels) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Internal error in PETSc, this array should not yet exist"); 152 153 mg->nlevels = levels; 154 mg->galerkin = PETSC_FALSE; 155 mg->galerkinused = PETSC_FALSE; 156 157 ierr = PetscMalloc(levels*sizeof(PC_MG*),&mglevels);CHKERRQ(ierr); 158 ierr = PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr); 159 160 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 161 162 for (i=0; i<levels; i++) { 163 ierr = PetscNewLog(pc,PC_MG_Levels,&mglevels[i]);CHKERRQ(ierr); 164 mglevels[i]->level = i; 165 mglevels[i]->levels = levels; 166 mglevels[i]->cycles = PC_MG_CYCLE_V; 167 mg->default_smoothu = 1; 168 mg->default_smoothd = 1; 169 170 if (comms) comm = comms[i]; 171 ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr); 172 ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr); 173 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);CHKERRQ(ierr); 174 ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr); 175 176 /* do special stuff for coarse grid */ 177 if (!i && levels > 1) { 178 ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr); 179 180 /* coarse solve is (redundant) LU by default */ 181 ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr); 182 ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr); 183 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 184 if (size > 1) { 185 ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr); 186 } else { 187 ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr); 188 } 189 190 } else { 191 char tprefix[128]; 192 sprintf(tprefix,"mg_levels_%d_",(int)i); 193 ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr); 194 } 195 ierr = PetscLogObjectParent(pc,mglevels[i]->smoothd);CHKERRQ(ierr); 196 mglevels[i]->smoothu = mglevels[i]->smoothd; 197 mg->rtol = 0.0; 198 mg->abstol = 0.0; 199 mg->dtol = 0.0; 200 mg->ttol = 0.0; 201 mg->eventsmoothsetup = 0; 202 mg->eventsmoothsolve = 0; 203 mg->eventresidual = 0; 204 mg->eventinterprestrict = 0; 205 mg->cyclesperpcapply = 1; 206 } 207 mg->am = PC_MG_MULTIPLICATIVE; 208 mg->levels = mglevels; 209 pc->ops->applyrichardson = PCApplyRichardson_MG; 210 PetscFunctionReturn(0); 211 } 212 213 #undef __FUNCT__ 214 #define __FUNCT__ "PCDestroy_MG_Private" 215 PetscErrorCode PCDestroy_MG_Private(PC pc) 216 { 217 PC_MG *mg = (PC_MG*)pc->data; 218 PC_MG_Levels **mglevels = mg->levels; 219 PetscErrorCode ierr; 220 PetscInt i,n; 221 222 PetscFunctionBegin; 223 if (mglevels) { 224 n = mglevels[0]->levels; 225 for (i=0; i<n-1; i++) { 226 if (mglevels[i+1]->r) {ierr = VecDestroy(mglevels[i+1]->r);CHKERRQ(ierr);} 227 if (mglevels[i]->b) {ierr = VecDestroy(mglevels[i]->b);CHKERRQ(ierr);} 228 if (mglevels[i]->x) {ierr = VecDestroy(mglevels[i]->x);CHKERRQ(ierr);} 229 if (mglevels[i+1]->restrct) {ierr = MatDestroy(mglevels[i+1]->restrct);CHKERRQ(ierr);} 230 if (mglevels[i+1]->interpolate) {ierr = MatDestroy(mglevels[i+1]->interpolate);CHKERRQ(ierr);} 231 } 232 233 for (i=0; i<n; i++) { 234 if (mglevels[i]->smoothd != mglevels[i]->smoothu) { 235 ierr = KSPDestroy(mglevels[i]->smoothd);CHKERRQ(ierr); 236 } 237 ierr = KSPDestroy(mglevels[i]->smoothu);CHKERRQ(ierr); 238 ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); 239 } 240 ierr = PetscFree(mglevels);CHKERRQ(ierr); 241 } 242 mg->nlevels = -1; 243 mg->levels = PETSC_NULL; 244 PetscFunctionReturn(0); 245 } 246 247 #undef __FUNCT__ 248 #define __FUNCT__ "PCDestroy_MG" 249 PetscErrorCode PCDestroy_MG(PC pc) 250 { 251 PC_MG *mg = (PC_MG*)pc->data; 252 PetscErrorCode ierr; 253 254 PetscFunctionBegin; 255 ierr = PCDestroy_MG_Private(pc);CHKERRQ(ierr); 256 ierr = PetscFree(mg);CHKERRQ(ierr); 257 PetscFunctionReturn(0); 258 } 259 260 261 262 EXTERN PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**); 263 EXTERN PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**); 264 EXTERN PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**); 265 266 /* 267 PCApply_MG - Runs either an additive, multiplicative, Kaskadic 268 or full cycle of multigrid. 269 270 Note: 271 A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 272 */ 273 #undef __FUNCT__ 274 #define __FUNCT__ "PCApply_MG" 275 static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x) 276 { 277 PC_MG *mg = (PC_MG*)pc->data; 278 PC_MG_Levels **mglevels = mg->levels; 279 PetscErrorCode ierr; 280 PetscInt levels = mglevels[0]->levels,i; 281 282 PetscFunctionBegin; 283 284 /* When the DM is supplying the matrix then it will not exist until here */ 285 for (i=0; i<levels-1; i++) { 286 if (!mglevels[i]->A) { 287 ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 288 } 289 } 290 291 mglevels[levels-1]->b = b; 292 mglevels[levels-1]->x = x; 293 if (mg->am == PC_MG_MULTIPLICATIVE) { 294 ierr = VecSet(x,0.0);CHKERRQ(ierr); 295 for (i=0; i<mg->cyclesperpcapply; i++) { 296 ierr = PCMGMCycle_Private(pc,mglevels+levels-1,PETSC_NULL);CHKERRQ(ierr); 297 } 298 } 299 else if (mg->am == PC_MG_ADDITIVE) { 300 ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr); 301 } 302 else if (mg->am == PC_MG_KASKADE) { 303 ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr); 304 } 305 else { 306 ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr); 307 } 308 PetscFunctionReturn(0); 309 } 310 311 312 #undef __FUNCT__ 313 #define __FUNCT__ "PCSetFromOptions_MG" 314 PetscErrorCode PCSetFromOptions_MG(PC pc) 315 { 316 PetscErrorCode ierr; 317 PetscInt m,levels = 1,cycles; 318 PetscTruth flg; 319 PC_MG *mg = (PC_MG*)pc->data; 320 PC_MG_Levels **mglevels = mg->levels; 321 PCMGType mgtype; 322 PCMGCycleType mgctype; 323 324 PetscFunctionBegin; 325 ierr = PetscOptionsHead("Multigrid options");CHKERRQ(ierr); 326 if (!mglevels) { 327 ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr); 328 ierr = PCMGSetLevels(pc,levels,PETSC_NULL);CHKERRQ(ierr); 329 mglevels = mg->levels; 330 } 331 mgctype = (PCMGCycleType) mglevels[0]->cycles; 332 ierr = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr); 333 if (flg) { 334 ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr); 335 }; 336 flg = PETSC_FALSE; 337 ierr = PetscOptionsTruth("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 338 if (flg) { 339 ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr); 340 } 341 ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);CHKERRQ(ierr); 342 if (flg) { 343 ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr); 344 } 345 ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);CHKERRQ(ierr); 346 if (flg) { 347 ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr); 348 } 349 mgtype = mg->am; 350 ierr = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr); 351 if (flg) { 352 ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr); 353 } 354 if (mg->am == PC_MG_MULTIPLICATIVE) { 355 ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr); 356 if (flg) { 357 ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr); 358 } 359 } 360 flg = PETSC_FALSE; 361 ierr = PetscOptionsTruth("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 362 if (flg) { 363 PetscInt i; 364 char eventname[128]; 365 if (!mg) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 366 levels = mglevels[0]->levels; 367 for (i=0; i<levels; i++) { 368 sprintf(eventname,"MGSetup Level %d",(int)i); 369 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mg->eventsmoothsetup);CHKERRQ(ierr); 370 sprintf(eventname,"MGSmooth Level %d",(int)i); 371 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mg->eventsmoothsolve);CHKERRQ(ierr); 372 if (i) { 373 sprintf(eventname,"MGResid Level %d",(int)i); 374 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mg->eventresidual);CHKERRQ(ierr); 375 sprintf(eventname,"MGInterp Level %d",(int)i); 376 ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mg->eventinterprestrict);CHKERRQ(ierr); 377 } 378 } 379 } 380 ierr = PetscOptionsTail();CHKERRQ(ierr); 381 PetscFunctionReturn(0); 382 } 383 384 const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0}; 385 const char *PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0}; 386 387 #undef __FUNCT__ 388 #define __FUNCT__ "PCView_MG" 389 PetscErrorCode PCView_MG(PC pc,PetscViewer viewer) 390 { 391 PC_MG *mg = (PC_MG*)pc->data; 392 PC_MG_Levels **mglevels = mg->levels; 393 PetscErrorCode ierr; 394 PetscInt levels = mglevels[0]->levels,i; 395 PetscTruth iascii; 396 397 PetscFunctionBegin; 398 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 399 if (iascii) { 400 ierr = PetscViewerASCIIPrintf(viewer," MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,(mglevels[0]->cycles == PC_MG_CYCLE_V) ? "v" : "w");CHKERRQ(ierr); 401 if (mg->am == PC_MG_MULTIPLICATIVE) { 402 ierr = PetscViewerASCIIPrintf(viewer," Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr); 403 } 404 if (mg->galerkin) { 405 ierr = PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 406 } else { 407 ierr = PetscViewerASCIIPrintf(viewer," Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr); 408 } 409 for (i=0; i<levels; i++) { 410 if (!i) { 411 ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D presmooths=%D postsmooths=%D -----\n",i,mg->default_smoothd,mg->default_smoothu);CHKERRQ(ierr); 412 } else { 413 ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D smooths=%D --------------------\n",i,mg->default_smoothd);CHKERRQ(ierr); 414 } 415 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 416 ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr); 417 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 418 if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) { 419 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr); 420 } else if (i){ 421 ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D smooths=%D --------------------\n",i,mg->default_smoothu);CHKERRQ(ierr); 422 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 423 ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr); 424 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 425 } 426 } 427 } else { 428 SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name); 429 } 430 PetscFunctionReturn(0); 431 } 432 433 /* 434 Calls setup for the KSP on each level 435 */ 436 #undef __FUNCT__ 437 #define __FUNCT__ "PCSetUp_MG" 438 PetscErrorCode PCSetUp_MG(PC pc) 439 { 440 PC_MG *mg = (PC_MG*)pc->data; 441 PC_MG_Levels **mglevels = mg->levels; 442 PetscErrorCode ierr; 443 PetscInt i,n = mglevels[0]->levels; 444 PC cpc,mpc; 445 PetscTruth preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump = PETSC_FALSE,opsset; 446 PetscViewerASCIIMonitor ascii; 447 PetscViewer viewer = PETSC_NULL; 448 MPI_Comm comm; 449 Mat dA,dB; 450 MatStructure uflag; 451 Vec tvec; 452 DM *dms; 453 454 PetscFunctionBegin; 455 456 /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */ 457 /* so use those from global PC */ 458 /* Is this what we always want? What if user wants to keep old one? */ 459 ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,PETSC_NULL,&opsset);CHKERRQ(ierr); 460 ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr); 461 ierr = KSPGetPC(mglevels[n-1]->smoothd,&mpc);CHKERRQ(ierr); 462 if (!opsset || ((cpc->setupcalled == 1) && (mpc->setupcalled == 2)) || ((mpc == cpc) && (mpc->setupcalled == 2))) { 463 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); 464 ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr); 465 } 466 467 if (pc->dm && !pc->setupcalled) { 468 /* construct the interpolation from the DMs */ 469 Mat p; 470 ierr = PetscMalloc(n*sizeof(DM),&dms);CHKERRQ(ierr); 471 dms[n-1] = pc->dm; 472 for (i=n-2; i>-1; i--) { 473 ierr = DMCoarsen(dms[i+1],PETSC_NULL,&dms[i]);CHKERRQ(ierr); 474 ierr = DMSetFunction(dms[i],0); 475 ierr = DMSetInitialGuess(dms[i],0); 476 if (!mglevels[i+1]->interpolate) { 477 ierr = DMGetInterpolation(dms[i],dms[i+1],&p,PETSC_NULL);CHKERRQ(ierr); 478 ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr); 479 ierr = MatDestroy(p);CHKERRQ(ierr); 480 } 481 } 482 483 if (!mg->galerkin) { 484 /* each coarse level gets its DM */ 485 for (i=n-2; i>-1; i--) { 486 ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr); 487 } 488 } 489 490 for (i=n-2; i>-1; i--) { 491 ierr = DMDestroy(dms[i]);CHKERRQ(ierr); 492 } 493 ierr = PetscFree(dms);CHKERRQ(ierr); 494 } 495 496 if (mg->galerkin) { 497 Mat B; 498 mg->galerkinused = PETSC_TRUE; 499 /* currently only handle case where mat and pmat are the same on coarser levels */ 500 ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB,&uflag);CHKERRQ(ierr); 501 if (!pc->setupcalled) { 502 for (i=n-2; i>-1; i--) { 503 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr); 504 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);CHKERRQ(ierr); 505 if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);} 506 dB = B; 507 } 508 } else { 509 for (i=n-2; i>-1; i--) { 510 ierr = KSPGetOperators(mglevels[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);CHKERRQ(ierr); 511 ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 512 ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);CHKERRQ(ierr); 513 dB = B; 514 } 515 } 516 } 517 518 if (!pc->setupcalled) { 519 ierr = PetscOptionsGetTruth(0,"-pc_mg_monitor",&monitor,PETSC_NULL);CHKERRQ(ierr); 520 521 for (i=0; i<n; i++) { 522 if (monitor) { 523 ierr = PetscObjectGetComm((PetscObject)mglevels[i]->smoothd,&comm);CHKERRQ(ierr); 524 ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr); 525 ierr = KSPMonitorSet(mglevels[i]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 526 } 527 ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr); 528 } 529 for (i=1; i<n; i++) { 530 if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) { 531 if (monitor) { 532 ierr = PetscObjectGetComm((PetscObject)mglevels[i]->smoothu,&comm);CHKERRQ(ierr); 533 ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr); 534 ierr = KSPMonitorSet(mglevels[i]->smoothu,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 535 } 536 ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr); 537 } 538 } 539 for (i=1; i<n; i++) { 540 if (!mglevels[i]->residual) { 541 Mat mat; 542 ierr = KSPGetOperators(mglevels[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);CHKERRQ(ierr); 543 ierr = PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);CHKERRQ(ierr); 544 } 545 if (mglevels[i]->restrct && !mglevels[i]->interpolate) { 546 ierr = PCMGSetInterpolation(pc,i,mglevels[i]->restrct);CHKERRQ(ierr); 547 } 548 if (!mglevels[i]->restrct && mglevels[i]->interpolate) { 549 ierr = PCMGSetRestriction(pc,i,mglevels[i]->interpolate);CHKERRQ(ierr); 550 } 551 #if defined(PETSC_USE_DEBUG) 552 if (!mglevels[i]->restrct || !mglevels[i]->interpolate) { 553 SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i); 554 } 555 #endif 556 } 557 for (i=0; i<n-1; i++) { 558 if (!mglevels[i]->b) { 559 Vec *vec; 560 ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vec,0,PETSC_NULL);CHKERRQ(ierr); 561 ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr); 562 ierr = VecDestroy(*vec);CHKERRQ(ierr); 563 ierr = PetscFree(vec);CHKERRQ(ierr); 564 } 565 if (!mglevels[i]->r && i) { 566 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 567 ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr); 568 ierr = VecDestroy(tvec);CHKERRQ(ierr); 569 } 570 if (!mglevels[i]->x) { 571 ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr); 572 ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr); 573 ierr = VecDestroy(tvec);CHKERRQ(ierr); 574 } 575 } 576 if (n != 1 && !mglevels[n-1]->r) { 577 /* PCMGSetR() on the finest level if user did not supply it */ 578 Vec *vec; 579 ierr = KSPGetVecs(mglevels[n-1]->smoothd,1,&vec,0,PETSC_NULL);CHKERRQ(ierr); 580 ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr); 581 ierr = VecDestroy(*vec);CHKERRQ(ierr); 582 ierr = PetscFree(vec);CHKERRQ(ierr); 583 } 584 } 585 586 587 for (i=1; i<n; i++) { 588 if (mglevels[i]->smoothu == mglevels[i]->smoothd) { 589 /* if doing only down then initial guess is zero */ 590 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr); 591 } 592 if (mg->eventsmoothsetup) {ierr = PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 593 ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr); 594 if (mg->eventsmoothsetup) {ierr = PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 595 } 596 for (i=1; i<n; i++) { 597 if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) { 598 Mat downmat,downpmat; 599 MatStructure matflag; 600 PetscTruth opsset; 601 602 /* check if operators have been set for up, if not use down operators to set them */ 603 ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,PETSC_NULL);CHKERRQ(ierr); 604 if (!opsset) { 605 ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat,&matflag);CHKERRQ(ierr); 606 ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat,matflag);CHKERRQ(ierr); 607 } 608 609 ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr); 610 if (mg->eventsmoothsetup) {ierr = PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 611 ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr); 612 if (mg->eventsmoothsetup) {ierr = PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 613 } 614 } 615 616 /* 617 If coarse solver is not direct method then DO NOT USE preonly 618 */ 619 ierr = PetscTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr); 620 if (preonly) { 621 ierr = PetscTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr); 622 ierr = PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr); 623 ierr = PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr); 624 if (!lu && !redundant && !cholesky) { 625 ierr = KSPSetType(mglevels[0]->smoothd,KSPGMRES);CHKERRQ(ierr); 626 } 627 } 628 629 if (!pc->setupcalled) { 630 if (monitor) { 631 ierr = PetscObjectGetComm((PetscObject)mglevels[0]->smoothd,&comm);CHKERRQ(ierr); 632 ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n,&ascii);CHKERRQ(ierr); 633 ierr = KSPMonitorSet(mglevels[0]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 634 } 635 ierr = KSPSetFromOptions(mglevels[0]->smoothd);CHKERRQ(ierr); 636 } 637 638 if (mg->eventsmoothsetup) {ierr = PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 639 ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr); 640 if (mg->eventsmoothsetup) {ierr = PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);} 641 642 /* 643 Dump the interpolation/restriction matrices plus the 644 Jacobian/stiffness on each level. This allows Matlab users to 645 easily check if the Galerkin condition A_c = R A_f R^T is satisfied. 646 647 Only support one or the other at the same time. 648 */ 649 #if defined(PETSC_USE_SOCKET_VIEWER) 650 ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,PETSC_NULL);CHKERRQ(ierr); 651 if (dump) { 652 viewer = PETSC_VIEWER_SOCKET_(((PetscObject)pc)->comm); 653 } 654 dump = PETSC_FALSE; 655 #endif 656 ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,PETSC_NULL);CHKERRQ(ierr); 657 if (dump) { 658 viewer = PETSC_VIEWER_BINARY_(((PetscObject)pc)->comm); 659 } 660 661 if (viewer) { 662 for (i=1; i<n; i++) { 663 ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr); 664 } 665 for (i=0; i<n; i++) { 666 ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr); 667 ierr = MatView(pc->mat,viewer);CHKERRQ(ierr); 668 } 669 } 670 PetscFunctionReturn(0); 671 } 672 673 /* -------------------------------------------------------------------------------------*/ 674 675 #undef __FUNCT__ 676 #define __FUNCT__ "PCMGGetLevels" 677 /*@ 678 PCMGGetLevels - Gets the number of levels to use with MG. 679 680 Not Collective 681 682 Input Parameter: 683 . pc - the preconditioner context 684 685 Output parameter: 686 . levels - the number of levels 687 688 Level: advanced 689 690 .keywords: MG, get, levels, multigrid 691 692 .seealso: PCMGSetLevels() 693 @*/ 694 PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetLevels(PC pc,PetscInt *levels) 695 { 696 PC_MG *mg = (PC_MG*)pc->data; 697 698 PetscFunctionBegin; 699 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 700 PetscValidIntPointer(levels,2); 701 *levels = mg->nlevels; 702 PetscFunctionReturn(0); 703 } 704 705 #undef __FUNCT__ 706 #define __FUNCT__ "PCMGSetType" 707 /*@ 708 PCMGSetType - Determines the form of multigrid to use: 709 multiplicative, additive, full, or the Kaskade algorithm. 710 711 Collective on PC 712 713 Input Parameters: 714 + pc - the preconditioner context 715 - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE, 716 PC_MG_FULL, PC_MG_KASKADE 717 718 Options Database Key: 719 . -pc_mg_type <form> - Sets <form>, one of multiplicative, 720 additive, full, kaskade 721 722 Level: advanced 723 724 .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid 725 726 .seealso: PCMGSetLevels() 727 @*/ 728 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetType(PC pc,PCMGType form) 729 { 730 PC_MG *mg = (PC_MG*)pc->data; 731 732 PetscFunctionBegin; 733 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 734 mg->am = form; 735 if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG; 736 else pc->ops->applyrichardson = 0; 737 PetscFunctionReturn(0); 738 } 739 740 #undef __FUNCT__ 741 #define __FUNCT__ "PCMGSetCycleType" 742 /*@ 743 PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more 744 complicated cycling. 745 746 Collective on PC 747 748 Input Parameters: 749 + pc - the multigrid context 750 - PC_MG_CYCLE_V or PC_MG_CYCLE_W 751 752 Options Database Key: 753 $ -pc_mg_cycle_type v or w 754 755 Level: advanced 756 757 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 758 759 .seealso: PCMGSetCycleTypeOnLevel() 760 @*/ 761 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetCycleType(PC pc,PCMGCycleType n) 762 { 763 PC_MG *mg = (PC_MG*)pc->data; 764 PC_MG_Levels **mglevels = mg->levels; 765 PetscInt i,levels; 766 767 PetscFunctionBegin; 768 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 769 if (!mglevels) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 770 levels = mglevels[0]->levels; 771 772 for (i=0; i<levels; i++) { 773 mglevels[i]->cycles = n; 774 } 775 PetscFunctionReturn(0); 776 } 777 778 #undef __FUNCT__ 779 #define __FUNCT__ "PCMGMultiplicativeSetCycles" 780 /*@ 781 PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 782 of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used 783 784 Collective on PC 785 786 Input Parameters: 787 + pc - the multigrid context 788 - n - number of cycles (default is 1) 789 790 Options Database Key: 791 $ -pc_mg_multiplicative_cycles n 792 793 Level: advanced 794 795 Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType() 796 797 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 798 799 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType() 800 @*/ 801 PetscErrorCode PETSCKSP_DLLEXPORT PCMGMultiplicativeSetCycles(PC pc,PetscInt n) 802 { 803 PC_MG *mg = (PC_MG*)pc->data; 804 PC_MG_Levels **mglevels = mg->levels; 805 PetscInt i,levels; 806 807 PetscFunctionBegin; 808 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 809 if (!mglevels) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 810 levels = mglevels[0]->levels; 811 812 for (i=0; i<levels; i++) { 813 mg->cyclesperpcapply = n; 814 } 815 PetscFunctionReturn(0); 816 } 817 818 #undef __FUNCT__ 819 #define __FUNCT__ "PCMGSetGalerkin" 820 /*@ 821 PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the 822 finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t 823 824 Collective on PC 825 826 Input Parameters: 827 . pc - the multigrid context 828 829 Options Database Key: 830 $ -pc_mg_galerkin 831 832 Level: intermediate 833 834 .keywords: MG, set, Galerkin 835 836 .seealso: PCMGGetGalerkin() 837 838 @*/ 839 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetGalerkin(PC pc) 840 { 841 PC_MG *mg = (PC_MG*)pc->data; 842 843 PetscFunctionBegin; 844 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 845 mg->galerkin = PETSC_TRUE; 846 PetscFunctionReturn(0); 847 } 848 849 #undef __FUNCT__ 850 #define __FUNCT__ "PCMGGetGalerkin" 851 /*@ 852 PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. 853 A_i-1 = r_i * A_i * r_i^t 854 855 Not Collective 856 857 Input Parameter: 858 . pc - the multigrid context 859 860 Output Parameter: 861 . gelerkin - PETSC_TRUE or PETSC_FALSE 862 863 Options Database Key: 864 $ -pc_mg_galerkin 865 866 Level: intermediate 867 868 .keywords: MG, set, Galerkin 869 870 .seealso: PCMGSetGalerkin() 871 872 @*/ 873 PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetGalerkin(PC pc,PetscTruth *galerkin) 874 { 875 PC_MG *mg = (PC_MG*)pc->data; 876 877 PetscFunctionBegin; 878 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 879 *galerkin = mg->galerkin; 880 PetscFunctionReturn(0); 881 } 882 883 #undef __FUNCT__ 884 #define __FUNCT__ "PCMGSetNumberSmoothDown" 885 /*@ 886 PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to 887 use on all levels. Use PCMGGetSmootherDown() to set different 888 pre-smoothing steps on different levels. 889 890 Collective on PC 891 892 Input Parameters: 893 + mg - the multigrid context 894 - n - the number of smoothing steps 895 896 Options Database Key: 897 . -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps 898 899 Level: advanced 900 901 .keywords: MG, smooth, down, pre-smoothing, steps, multigrid 902 903 .seealso: PCMGSetNumberSmoothUp() 904 @*/ 905 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothDown(PC pc,PetscInt n) 906 { 907 PC_MG *mg = (PC_MG*)pc->data; 908 PC_MG_Levels **mglevels = mg->levels; 909 PetscErrorCode ierr; 910 PetscInt i,levels; 911 912 PetscFunctionBegin; 913 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 914 if (!mglevels) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 915 levels = mglevels[0]->levels; 916 917 for (i=1; i<levels; i++) { 918 /* make sure smoother up and down are different */ 919 ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr); 920 ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 921 mg->default_smoothd = n; 922 } 923 PetscFunctionReturn(0); 924 } 925 926 #undef __FUNCT__ 927 #define __FUNCT__ "PCMGSetNumberSmoothUp" 928 /*@ 929 PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use 930 on all levels. Use PCMGGetSmootherUp() to set different numbers of 931 post-smoothing steps on different levels. 932 933 Collective on PC 934 935 Input Parameters: 936 + mg - the multigrid context 937 - n - the number of smoothing steps 938 939 Options Database Key: 940 . -pc_mg_smoothup <n> - Sets number of post-smoothing steps 941 942 Level: advanced 943 944 Note: this does not set a value on the coarsest grid, since we assume that 945 there is no separate smooth up on the coarsest grid. 946 947 .keywords: MG, smooth, up, post-smoothing, steps, multigrid 948 949 .seealso: PCMGSetNumberSmoothDown() 950 @*/ 951 PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothUp(PC pc,PetscInt n) 952 { 953 PC_MG *mg = (PC_MG*)pc->data; 954 PC_MG_Levels **mglevels = mg->levels; 955 PetscErrorCode ierr; 956 PetscInt i,levels; 957 958 PetscFunctionBegin; 959 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 960 if (!mglevels) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); 961 levels = mglevels[0]->levels; 962 963 for (i=1; i<levels; i++) { 964 /* make sure smoother up and down are different */ 965 ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr); 966 ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); 967 mg->default_smoothu = n; 968 } 969 PetscFunctionReturn(0); 970 } 971 972 /* ----------------------------------------------------------------------------------------*/ 973 974 /*MC 975 PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional 976 information about the coarser grid matrices and restriction/interpolation operators. 977 978 Options Database Keys: 979 + -pc_mg_levels <nlevels> - number of levels including finest 980 . -pc_mg_cycles v or w 981 . -pc_mg_smoothup <n> - number of smoothing steps after interpolation 982 . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator 983 . -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default 984 . -pc_mg_log - log information about time spent on each level of the solver 985 . -pc_mg_monitor - print information on the multigrid convergence 986 . -pc_mg_galerkin - use Galerkin process to compute coarser operators 987 - -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices 988 to the Socket viewer for reading from Matlab. 989 990 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 991 992 Level: intermediate 993 994 Concepts: multigrid/multilevel 995 996 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC 997 PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(), 998 PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(), 999 PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(), 1000 PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR() 1001 M*/ 1002 1003 EXTERN_C_BEGIN 1004 #undef __FUNCT__ 1005 #define __FUNCT__ "PCCreate_MG" 1006 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_MG(PC pc) 1007 { 1008 PC_MG *mg; 1009 PetscErrorCode ierr; 1010 1011 PetscFunctionBegin; 1012 ierr = PetscNewLog(pc,PC_MG,&mg);CHKERRQ(ierr); 1013 pc->data = (void*)mg; 1014 mg->nlevels = -1; 1015 1016 pc->ops->apply = PCApply_MG; 1017 pc->ops->setup = PCSetUp_MG; 1018 pc->ops->destroy = PCDestroy_MG; 1019 pc->ops->setfromoptions = PCSetFromOptions_MG; 1020 pc->ops->view = PCView_MG; 1021 PetscFunctionReturn(0); 1022 } 1023 EXTERN_C_END 1024