1 #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 2 #include <petscblaslapack.h> 3 #include <petscdm.h> 4 5 const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",NULL}; 6 const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",NULL}; 7 8 PetscErrorCode SNESReset_NGMRES(SNES snes) 9 { 10 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 11 PetscErrorCode ierr; 12 13 PetscFunctionBegin; 14 ierr = VecDestroyVecs(ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr); 15 ierr = VecDestroyVecs(ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr); 16 ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr); 17 PetscFunctionReturn(0); 18 } 19 20 PetscErrorCode SNESDestroy_NGMRES(SNES snes) 21 { 22 PetscErrorCode ierr; 23 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 24 25 PetscFunctionBegin; 26 ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr); 27 ierr = PetscFree4(ngmres->h,ngmres->beta,ngmres->xi,ngmres->q);CHKERRQ(ierr); 28 ierr = PetscFree3(ngmres->xnorms,ngmres->fnorms,ngmres->s);CHKERRQ(ierr); 29 #if defined(PETSC_USE_COMPLEX) 30 ierr = PetscFree(ngmres->rwork);CHKERRQ(ierr); 31 #endif 32 ierr = PetscFree(ngmres->work);CHKERRQ(ierr); 33 ierr = PetscFree(snes->data);CHKERRQ(ierr); 34 PetscFunctionReturn(0); 35 } 36 37 PetscErrorCode SNESSetUp_NGMRES(SNES snes) 38 { 39 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 40 const char *optionsprefix; 41 PetscInt msize,hsize; 42 PetscErrorCode ierr; 43 DM dm; 44 45 PetscFunctionBegin; 46 if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 47 SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function"); 48 } 49 if (snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED; 50 ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr); 51 52 if (!snes->vec_sol) { 53 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 54 ierr = DMCreateGlobalVector(dm,&snes->vec_sol);CHKERRQ(ierr); 55 } 56 57 if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);} 58 if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);} 59 if (!ngmres->setup_called) { 60 msize = ngmres->msize; /* restart size */ 61 hsize = msize * msize; 62 63 /* explicit least squares minimization solve */ 64 ierr = PetscCalloc4(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, hsize,&ngmres->q);CHKERRQ(ierr); 65 ierr = PetscMalloc3(msize,&ngmres->xnorms,msize,&ngmres->fnorms,msize,&ngmres->s);CHKERRQ(ierr); 66 ngmres->nrhs = 1; 67 ngmres->lda = msize; 68 ngmres->ldb = msize; 69 ngmres->lwork = 12*msize; 70 #if defined(PETSC_USE_COMPLEX) 71 ierr = PetscMalloc1(ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr); 72 #endif 73 ierr = PetscMalloc1(ngmres->lwork,&ngmres->work);CHKERRQ(ierr); 74 } 75 76 /* linesearch setup */ 77 ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr); 78 79 if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 80 ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr); 81 ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr); 82 if (!((PetscObject)ngmres->additive_linesearch)->type_name) { 83 ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr); 84 } 85 ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr); 86 ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr); 87 ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr); 88 } 89 90 ngmres->setup_called = PETSC_TRUE; 91 PetscFunctionReturn(0); 92 } 93 94 PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptionItems *PetscOptionsObject,SNES snes) 95 { 96 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 97 PetscErrorCode ierr; 98 PetscBool debug = PETSC_FALSE; 99 100 PetscFunctionBegin; 101 ierr = PetscOptionsHead(PetscOptionsObject,"SNES NGMRES options");CHKERRQ(ierr); 102 ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes, 103 (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr); 104 ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes, 105 (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr); 106 ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr); 107 ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr); 108 ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr); 109 ierr = PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr); 110 ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr); 111 ierr = PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr); 112 if (debug) { 113 ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes)); 114 } 115 ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr); 116 ierr = PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr); 117 ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr); 118 ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr); 119 ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr); 120 ierr = PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise",ngmres->restart_fm_rise,&ngmres->restart_fm_rise,NULL);CHKERRQ(ierr); 121 ierr = PetscOptionsTail();CHKERRQ(ierr); 122 if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA; 123 PetscFunctionReturn(0); 124 } 125 126 PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer) 127 { 128 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 129 PetscBool iascii; 130 PetscErrorCode ierr; 131 132 PetscFunctionBegin; 133 ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 134 if (iascii) { 135 ierr = PetscViewerASCIIPrintf(viewer," Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr); 136 ierr = PetscViewerASCIIPrintf(viewer," Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr); 137 ierr = PetscViewerASCIIPrintf(viewer," Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr); 138 ierr = PetscViewerASCIIPrintf(viewer," Restart on F_M residual increase: %s\n",ngmres->restart_fm_rise?"TRUE":"FALSE");CHKERRQ(ierr); 139 } 140 PetscFunctionReturn(0); 141 } 142 143 PetscErrorCode SNESSolve_NGMRES(SNES snes) 144 { 145 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 146 /* present solution, residual, and preconditioned residual */ 147 Vec X,F,B,D,Y; 148 149 /* candidate linear combination answers */ 150 Vec XA,FA,XM,FM; 151 152 /* coefficients and RHS to the minimization problem */ 153 PetscReal fnorm,fMnorm,fAnorm; 154 PetscReal xnorm,xMnorm,xAnorm; 155 PetscReal ynorm,yMnorm,yAnorm; 156 PetscInt k,k_restart,l,ivec,restart_count = 0; 157 158 /* solution selection data */ 159 PetscBool selectRestart; 160 /* 161 These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed 162 to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case 163 so the code is correct as written. 164 */ 165 PetscReal dnorm = 0.0,dminnorm = 0.0; 166 PetscReal fminnorm; 167 168 SNESConvergedReason reason; 169 SNESLineSearchReason lssucceed; 170 PetscErrorCode ierr; 171 172 PetscFunctionBegin; 173 if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 174 175 ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); 176 /* variable initialization */ 177 snes->reason = SNES_CONVERGED_ITERATING; 178 X = snes->vec_sol; 179 F = snes->vec_func; 180 B = snes->vec_rhs; 181 XA = snes->vec_sol_update; 182 FA = snes->work[0]; 183 D = snes->work[1]; 184 185 /* work for the line search */ 186 Y = snes->work[2]; 187 XM = snes->work[3]; 188 FM = snes->work[4]; 189 190 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 191 snes->iter = 0; 192 snes->norm = 0.; 193 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 194 195 /* initialization */ 196 197 if (snes->npc && snes->npcside== PC_LEFT) { 198 ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr); 199 ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr); 200 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 201 snes->reason = SNES_DIVERGED_INNER; 202 PetscFunctionReturn(0); 203 } 204 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 205 } else { 206 if (!snes->vec_func_init_set) { 207 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 208 } else snes->vec_func_init_set = PETSC_FALSE; 209 210 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 211 SNESCheckFunctionNorm(snes,fnorm); 212 } 213 fminnorm = fnorm; 214 215 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 216 snes->norm = fnorm; 217 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 218 ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); 219 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 220 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 221 if (snes->reason) PetscFunctionReturn(0); 222 SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X); 223 224 k_restart = 1; 225 l = 1; 226 ivec = 0; 227 for (k=1; k < snes->max_its+1; k++) { 228 /* Computation of x^M */ 229 if (snes->npc && snes->npcside== PC_RIGHT) { 230 ierr = VecCopy(X,XM);CHKERRQ(ierr); 231 ierr = SNESSetInitialFunction(snes->npc,F);CHKERRQ(ierr); 232 233 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->npc,XM,B,0);CHKERRQ(ierr); 234 ierr = SNESSolve(snes->npc,B,XM);CHKERRQ(ierr); 235 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->npc,XM,B,0);CHKERRQ(ierr); 236 237 ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr); 238 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 239 snes->reason = SNES_DIVERGED_INNER; 240 PetscFunctionReturn(0); 241 } 242 ierr = SNESGetNPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr); 243 } else { 244 /* no preconditioner -- just take gradient descent with line search */ 245 ierr = VecCopy(F,Y);CHKERRQ(ierr); 246 ierr = VecCopy(F,FM);CHKERRQ(ierr); 247 ierr = VecCopy(X,XM);CHKERRQ(ierr); 248 249 fMnorm = fnorm; 250 251 ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr); 252 ierr = SNESLineSearchGetReason(snes->linesearch,&lssucceed);CHKERRQ(ierr); 253 if (lssucceed) { 254 if (++snes->numFailures >= snes->maxFailures) { 255 snes->reason = SNES_DIVERGED_LINE_SEARCH; 256 PetscFunctionReturn(0); 257 } 258 } 259 } 260 261 ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr); 262 /* r = F(x) */ 263 if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */ 264 265 /* differences for selection and restart */ 266 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 267 ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr); 268 } else { 269 ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr); 270 } 271 SNESCheckFunctionNorm(snes,fnorm); 272 273 /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 274 ierr = SNESNGMRESSelect_Private(snes,k_restart,XM,FM,xMnorm,fMnorm,yMnorm,XA,FA,xAnorm,fAnorm,yAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&xnorm,&fnorm,&ynorm);CHKERRQ(ierr); 275 selectRestart = PETSC_FALSE; 276 277 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { 278 ierr = SNESNGMRESSelectRestart_Private(snes,l,fMnorm,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr); 279 280 /* if the restart conditions persist for more than restart_it iterations, restart. */ 281 if (selectRestart) restart_count++; 282 else restart_count = 0; 283 } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { 284 if (k_restart > ngmres->restart_periodic) { 285 if (ngmres->monitor) {ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);} 286 restart_count = ngmres->restart_it; 287 } 288 } 289 290 ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */ 291 292 /* restart after restart conditions have persisted for a fixed number of iterations */ 293 if (restart_count >= ngmres->restart_it) { 294 if (ngmres->monitor) { 295 ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr); 296 } 297 restart_count = 0; 298 k_restart = 1; 299 l = 1; 300 ivec = 0; 301 /* q_{00} = nu */ 302 ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr); 303 } else { 304 /* select the current size of the subspace */ 305 if (l < ngmres->msize) l++; 306 k_restart++; 307 /* place the current entry in the list of previous entries */ 308 if (ngmres->candidate) { 309 if (fminnorm > fMnorm) fminnorm = fMnorm; 310 ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr); 311 } else { 312 if (fminnorm > fnorm) fminnorm = fnorm; 313 ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr); 314 } 315 } 316 317 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 318 snes->iter = k; 319 snes->norm = fnorm; 320 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 321 ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 322 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 323 ierr = (*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 324 if (snes->reason) PetscFunctionReturn(0); 325 } 326 snes->reason = SNES_DIVERGED_MAX_IT; 327 PetscFunctionReturn(0); 328 } 329 330 /*@ 331 SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M 332 333 Input Parameters: 334 + snes - the SNES context. 335 - flg - boolean value deciding whether to use the option or not 336 337 Options Database: 338 + -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M 339 340 Level: intermediate 341 342 Notes: 343 If the proposed step x_M increases the residual F_M, it might be trying to get out of a stagnation area. 344 To help the solver do that, reset the Krylov subspace whenever F_M increases. 345 346 This option must be used with SNES_NGMRES_RESTART_DIFFERENCE 347 348 The default is FALSE. 349 .seealso: SNES_NGMRES_RESTART_DIFFERENCE 350 @*/ 351 PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes,PetscBool flg) 352 { 353 PetscErrorCode (*f)(SNES,PetscBool); 354 PetscErrorCode ierr; 355 356 PetscFunctionBegin; 357 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",&f);CHKERRQ(ierr); 358 if (f) {ierr = (f)(snes,flg);CHKERRQ(ierr);} 359 PetscFunctionReturn(0); 360 } 361 362 PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes,PetscBool flg) 363 { 364 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 365 366 PetscFunctionBegin; 367 ngmres->restart_fm_rise = flg; 368 PetscFunctionReturn(0); 369 } 370 371 PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes,PetscBool *flg) 372 { 373 PetscErrorCode (*f)(SNES,PetscBool*); 374 PetscErrorCode ierr; 375 376 PetscFunctionBegin; 377 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",&f);CHKERRQ(ierr); 378 if (f) {ierr = (f)(snes,flg);CHKERRQ(ierr);} 379 PetscFunctionReturn(0); 380 } 381 382 PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes,PetscBool *flg) 383 { 384 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 385 386 PetscFunctionBegin; 387 *flg = ngmres->restart_fm_rise; 388 PetscFunctionReturn(0); 389 } 390 391 /*@ 392 SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES. 393 394 Logically Collective on SNES 395 396 Input Parameters: 397 + snes - the iterative context 398 - rtype - restart type 399 400 Options Database: 401 + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 402 - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 403 404 Level: intermediate 405 406 SNESNGMRESRestartTypes: 407 + SNES_NGMRES_RESTART_NONE - never restart 408 . SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria 409 - SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations 410 411 Notes: 412 The default line search used is the L2 line search and it requires two additional function evaluations. 413 414 @*/ 415 PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype) 416 { 417 PetscErrorCode ierr; 418 419 PetscFunctionBegin; 420 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 421 ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr); 422 PetscFunctionReturn(0); 423 } 424 425 /*@ 426 SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES. This determines how the candidate solution and 427 combined solution are used to create the next iterate. 428 429 Logically Collective on SNES 430 431 Input Parameters: 432 + snes - the iterative context 433 - stype - selection type 434 435 Options Database: 436 . -snes_ngmres_select_type<difference,none,linesearch> 437 438 Level: intermediate 439 440 SNESNGMRESSelectTypes: 441 + SNES_NGMRES_SELECT_NONE - choose the combined solution all the time 442 . SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria 443 - SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination 444 445 Notes: 446 The default line search used is the L2 line search and it requires two additional function evaluations. 447 448 @*/ 449 PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype) 450 { 451 PetscErrorCode ierr; 452 453 PetscFunctionBegin; 454 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 455 ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr); 456 PetscFunctionReturn(0); 457 } 458 459 PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype) 460 { 461 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 462 463 PetscFunctionBegin; 464 ngmres->select_type = stype; 465 PetscFunctionReturn(0); 466 } 467 468 PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype) 469 { 470 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 471 472 PetscFunctionBegin; 473 ngmres->restart_type = rtype; 474 PetscFunctionReturn(0); 475 } 476 477 /*MC 478 SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 479 480 Level: beginner 481 482 Options Database: 483 + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 484 . -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 485 . -snes_ngmres_candidate - Use NGMRES variant which combines candidate solutions instead of actual solutions 486 . -snes_ngmres_m - Number of stored previous solutions and residuals 487 . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 488 . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 489 . -snes_ngmres_gammaC - Residual tolerance for restart 490 . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 491 . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 492 . -snes_ngmres_restart_fm_rise - Restart on residual rise from x_M step 493 . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 494 . -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother 495 - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 496 497 Notes: 498 499 The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 500 optimization problem at each iteration. 501 502 Very similar to the SNESANDERSON algorithm. 503 504 References: 505 + 1. - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", 506 SIAM Journal on Scientific Computing, 21(5), 2000. 507 - 2. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 508 SIAM Review, 57(4), 2015 509 510 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 511 M*/ 512 513 PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes) 514 { 515 SNES_NGMRES *ngmres; 516 PetscErrorCode ierr; 517 SNESLineSearch linesearch; 518 519 PetscFunctionBegin; 520 snes->ops->destroy = SNESDestroy_NGMRES; 521 snes->ops->setup = SNESSetUp_NGMRES; 522 snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 523 snes->ops->view = SNESView_NGMRES; 524 snes->ops->solve = SNESSolve_NGMRES; 525 snes->ops->reset = SNESReset_NGMRES; 526 527 snes->usesnpc = PETSC_TRUE; 528 snes->usesksp = PETSC_FALSE; 529 snes->npcside = PC_RIGHT; 530 531 snes->alwayscomputesfinalresidual = PETSC_TRUE; 532 533 ierr = PetscNewLog(snes,&ngmres);CHKERRQ(ierr); 534 snes->data = (void*) ngmres; 535 ngmres->msize = 30; 536 537 if (!snes->tolerancesset) { 538 snes->max_funcs = 30000; 539 snes->max_its = 10000; 540 } 541 542 ngmres->candidate = PETSC_FALSE; 543 544 ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr); 545 if (!((PetscObject)linesearch)->type_name) { 546 ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr); 547 } 548 549 ngmres->additive_linesearch = NULL; 550 ngmres->approxfunc = PETSC_FALSE; 551 ngmres->restart_it = 2; 552 ngmres->restart_periodic = 30; 553 ngmres->gammaA = 2.0; 554 ngmres->gammaC = 2.0; 555 ngmres->deltaB = 0.9; 556 ngmres->epsilonB = 0.1; 557 ngmres->restart_fm_rise = PETSC_FALSE; 558 559 ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 560 ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 561 562 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr); 563 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr); 564 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",SNESNGMRESSetRestartFmRise_NGMRES);CHKERRQ(ierr); 565 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",SNESNGMRESGetRestartFmRise_NGMRES);CHKERRQ(ierr); 566 PetscFunctionReturn(0); 567 } 568