1 #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 2 #include <petscblaslapack.h> 3 4 const char *SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0}; 5 const char *SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",0}; 6 7 #undef __FUNCT__ 8 #define __FUNCT__ "SNESReset_NGMRES" 9 PetscErrorCode SNESReset_NGMRES(SNES snes) 10 { 11 SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 12 PetscErrorCode ierr; 13 14 PetscFunctionBegin; 15 ierr = VecDestroyVecs(ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr); 16 ierr = VecDestroyVecs(ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr); 17 ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr); 18 19 PetscFunctionReturn(0); 20 } 21 22 #undef __FUNCT__ 23 #define __FUNCT__ "SNESDestroy_NGMRES" 24 PetscErrorCode SNESDestroy_NGMRES(SNES snes) 25 { 26 PetscErrorCode ierr; 27 SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 28 29 PetscFunctionBegin; 30 ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr); 31 ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->fnorms, ngmres->q);CHKERRQ(ierr); 32 ierr = PetscFree(ngmres->s);CHKERRQ(ierr); 33 ierr = PetscFree(ngmres->xnorms);CHKERRQ(ierr); 34 #if PETSC_USE_COMPLEX 35 ierr = PetscFree(ngmres->rwork); 36 #endif 37 ierr = PetscFree(ngmres->work); 38 ierr = PetscFree(snes->data); 39 PetscFunctionReturn(0); 40 } 41 42 #undef __FUNCT__ 43 #define __FUNCT__ "SNESSetUp_NGMRES" 44 PetscErrorCode SNESSetUp_NGMRES(SNES snes) 45 { 46 SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 47 const char *optionsprefix; 48 PetscInt msize,hsize; 49 PetscErrorCode ierr; 50 51 PetscFunctionBegin; 52 ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr); 53 if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);} 54 if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);} 55 if (!ngmres->setup_called) { 56 msize = ngmres->msize; /* restart size */ 57 hsize = msize * msize; 58 59 /* explicit least squares minimization solve */ 60 ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h, 61 msize,PetscScalar,&ngmres->beta, 62 msize,PetscScalar,&ngmres->xi, 63 msize,PetscReal, &ngmres->fnorms, 64 hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr); 65 if (ngmres->singlereduction) { 66 ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr); 67 } 68 ngmres->nrhs = 1; 69 ngmres->lda = msize; 70 ngmres->ldb = msize; 71 ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr); 72 ierr = PetscMemzero(ngmres->h, hsize*sizeof(PetscScalar));CHKERRQ(ierr); 73 ierr = PetscMemzero(ngmres->q, hsize*sizeof(PetscScalar));CHKERRQ(ierr); 74 ierr = PetscMemzero(ngmres->xi, msize*sizeof(PetscScalar));CHKERRQ(ierr); 75 ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr); 76 ngmres->lwork = 12*msize; 77 #if PETSC_USE_COMPLEX 78 ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork); 79 #endif 80 ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work); 81 } 82 83 /* linesearch setup */ 84 ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); 85 86 if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 87 ierr = SNESLineSearchCreate(((PetscObject)snes)->comm, &ngmres->additive_linesearch);CHKERRQ(ierr); 88 ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch, snes);CHKERRQ(ierr); 89 ierr = SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2);CHKERRQ(ierr); 90 ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_");CHKERRQ(ierr); 91 ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix);CHKERRQ(ierr); 92 ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr); 93 } 94 95 ngmres->setup_called = PETSC_TRUE; 96 PetscFunctionReturn(0); 97 } 98 99 #undef __FUNCT__ 100 #define __FUNCT__ "SNESSetFromOptions_NGMRES" 101 PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes) 102 { 103 SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 104 PetscErrorCode ierr; 105 PetscBool debug; 106 SNESLineSearch linesearch; 107 PetscFunctionBegin; 108 ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr); 109 ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes, 110 (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,PETSC_NULL);CHKERRQ(ierr); 111 ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes, 112 (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,PETSC_NULL);CHKERRQ(ierr); 113 ierr = PetscOptionsBool("-snes_ngmres_anderson", "Use Anderson mixing storage", "SNES", ngmres->anderson, &ngmres->anderson, PETSC_NULL);CHKERRQ(ierr); 114 ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr); 115 ierr = PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES", ngmres->restart_periodic, &ngmres->restart_periodic, PETSC_NULL);CHKERRQ(ierr); 116 ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES", ngmres->restart_it, &ngmres->restart_it, PETSC_NULL);CHKERRQ(ierr); 117 ierr = PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr); 118 if (debug) { 119 ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 120 } 121 ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr); 122 ierr = PetscOptionsReal("-snes_ngmres_gammaC", " Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr); 123 ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr); 124 ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr); 125 ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES", ngmres->singlereduction, &ngmres->singlereduction, PETSC_NULL);CHKERRQ(ierr); 126 ierr = PetscOptionsTail();CHKERRQ(ierr); 127 if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA; 128 129 /* set the default type of the line search if the user hasn't already. */ 130 if (!snes->linesearch) { 131 ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr); 132 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr); 133 } 134 PetscFunctionReturn(0); 135 } 136 137 #undef __FUNCT__ 138 #define __FUNCT__ "SNESView_NGMRES" 139 PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer) 140 { 141 SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 142 PetscBool iascii; 143 PetscErrorCode ierr; 144 145 PetscFunctionBegin; 146 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 147 if (iascii) { 148 149 ierr = PetscViewerASCIIPrintf(viewer, " Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr); 150 ierr = PetscViewerASCIIPrintf(viewer, " Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr); 151 ierr = PetscViewerASCIIPrintf(viewer, " Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr); 152 } 153 PetscFunctionReturn(0); 154 } 155 156 #undef __FUNCT__ 157 #define __FUNCT__ "SNESSolve_NGMRES" 158 159 PetscErrorCode SNESSolve_NGMRES(SNES snes) 160 { 161 SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 162 /* present solution, residual, and preconditioned residual */ 163 Vec X, F, B, D, Y; 164 165 /* candidate linear combination answers */ 166 Vec XA, FA, XM, FM, FPC; 167 168 /* previous iterations to construct the subspace */ 169 Vec *Fdot = ngmres->Fdot; 170 Vec *Xdot = ngmres->Xdot; 171 172 /* coefficients and RHS to the minimization problem */ 173 PetscScalar *beta = ngmres->beta; 174 PetscScalar *xi = ngmres->xi; 175 PetscReal fnorm, fMnorm, fAnorm; 176 PetscReal nu; 177 PetscScalar alph_total = 0.; 178 PetscInt i, j, k, k_restart, l, ivec, restart_count = 0; 179 180 /* solution selection data */ 181 PetscBool selectA, selectRestart; 182 PetscReal dnorm, dminnorm = 0.0, dcurnorm; 183 PetscReal fminnorm; 184 185 SNESConvergedReason reason; 186 PetscBool lssucceed,changed_y,changed_w; 187 PetscErrorCode ierr; 188 189 PetscFunctionBegin; 190 /* variable initialization */ 191 snes->reason = SNES_CONVERGED_ITERATING; 192 X = snes->vec_sol; 193 F = snes->vec_func; 194 B = snes->vec_rhs; 195 XA = snes->vec_sol_update; 196 FA = snes->work[0]; 197 D = snes->work[1]; 198 199 /* work for the line search */ 200 Y = snes->work[2]; 201 XM = snes->work[3]; 202 FM = snes->work[4]; 203 204 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 205 snes->iter = 0; 206 snes->norm = 0.; 207 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 208 209 /* initialization */ 210 211 /* r = F(x) */ 212 if (!snes->vec_func_init_set) { 213 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 214 if (snes->domainerror) { 215 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 216 PetscFunctionReturn(0); 217 } 218 } else { 219 snes->vec_func_init_set = PETSC_FALSE; 220 } 221 222 if (!snes->norm_init_set) { 223 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 224 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation"); 225 } else { 226 fnorm = snes->norm_init; 227 snes->norm_init_set = PETSC_FALSE; 228 } 229 fminnorm = fnorm; 230 /* nu = (r, r) */ 231 nu = fnorm*fnorm; 232 233 /* q_{00} = nu */ 234 Q(0,0) = nu; 235 ngmres->fnorms[0] = fnorm; 236 /* Fdot[0] = F */ 237 ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr); 238 ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr); 239 240 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 241 snes->norm = fnorm; 242 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 243 SNESLogConvHistory(snes, fnorm, 0); 244 ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr); 245 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 246 if (snes->reason) PetscFunctionReturn(0); 247 248 k_restart = 1; 249 l = 1; 250 for (k=1; k < snes->max_its+1; k++) { 251 /* select which vector of the stored subspace will be updated */ 252 ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */ 253 254 /* Computation of x^M */ 255 if (snes->pc) { 256 ierr = VecCopy(X, XM);CHKERRQ(ierr); 257 ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); 258 ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); 259 ierr = SNESSolve(snes->pc, B, XM);CHKERRQ(ierr); 260 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 261 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 262 snes->reason = SNES_DIVERGED_INNER; 263 PetscFunctionReturn(0); 264 } 265 ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 266 ierr = VecCopy(FPC, FM);CHKERRQ(ierr); 267 ierr = SNESGetFunctionNorm(snes->pc, &fMnorm);CHKERRQ(ierr); 268 } else { 269 /* no preconditioner -- just take gradient descent with line search */ 270 ierr = VecCopy(F, Y);CHKERRQ(ierr); 271 ierr = VecCopy(F, FM);CHKERRQ(ierr); 272 ierr = VecCopy(X, XM);CHKERRQ(ierr); 273 fMnorm = fnorm; 274 ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr); 275 ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 276 if (!lssucceed) { 277 if (++snes->numFailures >= snes->maxFailures) { 278 snes->reason = SNES_DIVERGED_LINE_SEARCH; 279 PetscFunctionReturn(0); 280 } 281 } 282 } 283 284 /* r = F(x) */ 285 nu = fMnorm*fMnorm; 286 if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */ 287 288 /* construct the right hand side and xi factors */ 289 ierr = VecMDot(FM, l, Fdot, xi);CHKERRQ(ierr); 290 291 for (i = 0; i < l; i++) { 292 beta[i] = nu - xi[i]; 293 } 294 295 /* construct h */ 296 for (j = 0; j < l; j++) { 297 for (i = 0; i < l; i++) { 298 H(i, j) = Q(i, j) - xi[i] - xi[j] + nu; 299 } 300 } 301 302 if(l == 1) { 303 /* simply set alpha[0] = beta[0] / H[0, 0] */ 304 if (H(0, 0) != 0.) { 305 beta[0] = beta[0] / H(0, 0); 306 } else { 307 beta[0] = 0.; 308 } 309 } else { 310 #ifdef PETSC_MISSING_LAPACK_GELSS 311 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine."); 312 #else 313 ngmres->m = PetscBLASIntCast(l); 314 ngmres->n = PetscBLASIntCast(l); 315 ngmres->info = PetscBLASIntCast(0); 316 ngmres->rcond = -1.; 317 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 318 #ifdef PETSC_USE_COMPLEX 319 LAPACKgelss_(&ngmres->m, 320 &ngmres->n, 321 &ngmres->nrhs, 322 ngmres->h, 323 &ngmres->lda, 324 ngmres->beta, 325 &ngmres->ldb, 326 ngmres->s, 327 &ngmres->rcond, 328 &ngmres->rank, 329 ngmres->work, 330 &ngmres->lwork, 331 ngmres->rwork, 332 &ngmres->info); 333 #else 334 LAPACKgelss_(&ngmres->m, 335 &ngmres->n, 336 &ngmres->nrhs, 337 ngmres->h, 338 &ngmres->lda, 339 ngmres->beta, 340 &ngmres->ldb, 341 ngmres->s, 342 &ngmres->rcond, 343 &ngmres->rank, 344 ngmres->work, 345 &ngmres->lwork, 346 &ngmres->info); 347 #endif 348 ierr = PetscFPTrapPop();CHKERRQ(ierr); 349 if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS"); 350 if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge"); 351 #endif 352 } 353 354 alph_total = 0.; 355 for (i = 0; i < l; i++) { 356 alph_total += beta[i]; 357 } 358 359 ierr = VecCopy(XM, XA);CHKERRQ(ierr); 360 ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr); 361 362 ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr); 363 364 /* check the validity of the step */ 365 ierr = VecCopy(XA,Y);CHKERRQ(ierr); 366 ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr); 367 ierr = SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);CHKERRQ(ierr); 368 ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr); 369 370 /* differences for selection and restart */ 371 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 372 if (ngmres->singlereduction) { 373 dminnorm = -1.0; 374 ierr=VecCopy(XA, D);CHKERRQ(ierr); 375 ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr); 376 for(i=0;i<l;i++) { 377 ierr=VecAXPY(Xdot[i],-1.0,XA);CHKERRQ(ierr); 378 } 379 ierr = VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 380 ierr = VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr); 381 for (i=0;i<l;i++) { 382 ierr = VecNormBegin(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr); 383 } 384 ierr = VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 385 ierr = VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr); 386 for (i=0;i<l;i++) { 387 ierr = VecNormEnd(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr); 388 } 389 for(i=0;i<l;i++) { 390 dcurnorm = ngmres->xnorms[i]; 391 if ((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm; 392 ierr=VecAXPY(Xdot[i],1.0,XA);CHKERRQ(ierr); 393 } 394 } else { 395 ierr=VecCopy(XA, D);CHKERRQ(ierr); 396 ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr); 397 ierr=VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr); 398 ierr=VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 399 ierr=VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr); 400 ierr=VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 401 dminnorm = -1.0; 402 for(i=0;i<l;i++) { 403 ierr=VecCopy(XA, D);CHKERRQ(ierr); 404 ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr); 405 ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr); 406 if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm; 407 } 408 } 409 } else { 410 ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 411 } 412 /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 413 if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 414 /* X = X + \lambda(XA - X) */ 415 if (ngmres->monitor) { 416 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 417 } 418 ierr = VecCopy(FM, F);CHKERRQ(ierr); 419 ierr = VecCopy(XM, X);CHKERRQ(ierr); 420 ierr = VecCopy(XA, Y);CHKERRQ(ierr); 421 fnorm = fMnorm; 422 ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr); 423 ierr = SNESLineSearchApply(ngmres->additive_linesearch,X,F,&fnorm,Y);CHKERRQ(ierr); 424 ierr = SNESLineSearchGetSuccess(ngmres->additive_linesearch, &lssucceed);CHKERRQ(ierr); 425 if (!lssucceed) { 426 if (++snes->numFailures >= snes->maxFailures) { 427 snes->reason = SNES_DIVERGED_LINE_SEARCH; 428 PetscFunctionReturn(0); 429 } 430 } 431 if (ngmres->monitor) { 432 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", fnorm);CHKERRQ(ierr); 433 } 434 } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 435 selectA = PETSC_TRUE; 436 /* Conditions for choosing the accelerated answer */ 437 /* Criterion A -- the norm of the function isn't increased above the minimum by too much */ 438 if (fAnorm >= ngmres->gammaA*fminnorm) { 439 selectA = PETSC_FALSE; 440 } 441 /* Criterion B -- the choice of x^A isn't too close to some other choice */ 442 if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) { 443 } else { 444 selectA=PETSC_FALSE; 445 } 446 if (selectA) { 447 if (ngmres->monitor) { 448 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 449 } 450 /* copy it over */ 451 fnorm = fAnorm; 452 nu = fnorm*fnorm; 453 ierr = VecCopy(FA, F);CHKERRQ(ierr); 454 ierr = VecCopy(XA, X);CHKERRQ(ierr); 455 } else { 456 if (ngmres->monitor) { 457 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr); 458 } 459 fnorm = fMnorm; 460 nu = fnorm*fnorm; 461 ierr = VecCopy(FM, F);CHKERRQ(ierr); 462 ierr = VecCopy(XM, X);CHKERRQ(ierr); 463 } 464 } else { /* none */ 465 fnorm = fAnorm; 466 nu = fnorm*fnorm; 467 ierr = VecCopy(FA, F);CHKERRQ(ierr); 468 ierr = VecCopy(XA, X);CHKERRQ(ierr); 469 } 470 471 selectRestart = PETSC_FALSE; 472 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { 473 /* difference stagnation restart */ 474 if((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm))) { 475 if (ngmres->monitor) { 476 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr); 477 } 478 selectRestart = PETSC_TRUE; 479 } 480 /* residual stagnation restart */ 481 if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) { 482 if (ngmres->monitor) { 483 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", PetscSqrtReal(fAnorm), ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr); 484 } 485 selectRestart = PETSC_TRUE; 486 } 487 /* if the restart conditions persist for more than restart_it iterations, restart. */ 488 if (selectRestart) { 489 restart_count++; 490 } else { 491 restart_count = 0; 492 } 493 } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { 494 if (k_restart > ngmres->restart_periodic) { 495 if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %D iterations\n", k_restart);CHKERRQ(ierr); 496 restart_count = ngmres->restart_it; 497 } 498 } 499 /* restart after restart conditions have persisted for a fixed number of iterations */ 500 if (restart_count >= ngmres->restart_it) { 501 if (ngmres->monitor){ 502 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr); 503 } 504 restart_count = 0; 505 k_restart = 1; 506 l = 1; 507 /* q_{00} = nu */ 508 if (ngmres->anderson) { 509 ngmres->fnorms[0] = fMnorm; 510 nu = fMnorm*fMnorm; 511 Q(0,0) = nu; 512 /* Fdot[0] = F */ 513 ierr = VecCopy(XM, Xdot[0]);CHKERRQ(ierr); 514 ierr = VecCopy(FM, Fdot[0]);CHKERRQ(ierr); 515 } else { 516 ngmres->fnorms[0] = fnorm; 517 nu = fnorm*fnorm; 518 Q(0,0) = nu; 519 /* Fdot[0] = F */ 520 ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr); 521 ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr); 522 } 523 } else { 524 /* select the current size of the subspace */ 525 if (l < ngmres->msize) l++; 526 k_restart++; 527 /* place the current entry in the list of previous entries */ 528 if (ngmres->anderson) { 529 ierr = VecCopy(FM, Fdot[ivec]);CHKERRQ(ierr); 530 ierr = VecCopy(XM, Xdot[ivec]);CHKERRQ(ierr); 531 ngmres->fnorms[ivec] = fMnorm; 532 if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of FM */ 533 xi[ivec] = fMnorm*fMnorm; 534 for (i = 0; i < l; i++) { 535 Q(i, ivec) = xi[i]; 536 Q(ivec, i) = xi[i]; 537 } 538 } else { 539 ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr); 540 ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr); 541 ngmres->fnorms[ivec] = fnorm; 542 if (fminnorm > fnorm) fminnorm = fnorm; /* the minimum norm is now of FA */ 543 ierr = VecMDot(F, l, Fdot, xi);CHKERRQ(ierr); 544 for (i = 0; i < l; i++) { 545 Q(i, ivec) = xi[i]; 546 Q(ivec, i) = xi[i]; 547 } 548 } 549 } 550 551 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 552 snes->iter = k; 553 snes->norm = fnorm; 554 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 555 SNESLogConvHistory(snes, snes->norm, snes->iter); 556 ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr); 557 558 ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 559 if (snes->reason) PetscFunctionReturn(0); 560 } 561 snes->reason = SNES_DIVERGED_MAX_IT; 562 PetscFunctionReturn(0); 563 } 564 565 #undef __FUNCT__ 566 #define __FUNCT__ "SNESNGMRESSetRestartType" 567 /*@ 568 SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES. 569 570 Logically Collective on SNES 571 572 Input Parameters: 573 + snes - the iterative context 574 - rtype - restart type 575 576 Options Database: 577 + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 578 - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 579 580 Level: intermediate 581 582 SNESNGMRESRestartTypes: 583 + SNES_NGMRES_RESTART_NONE - never restart 584 . SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria 585 - SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations 586 587 Notes: 588 The default line search used is the L2 line search and it requires two additional function evaluations. 589 590 .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch 591 @*/ 592 PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype) { 593 PetscErrorCode ierr; 594 PetscFunctionBegin; 595 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 596 ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr); 597 PetscFunctionReturn(0); 598 } 599 600 #undef __FUNCT__ 601 #define __FUNCT__ "SNESNGMRESSetSelectType" 602 /*@ 603 SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES. This determines how the candidate solution and 604 combined solution are used to create the next iterate. 605 606 Logically Collective on SNES 607 608 Input Parameters: 609 + snes - the iterative context 610 - stype - selection type 611 612 Options Database: 613 . -snes_ngmres_select_type<difference,none,linesearch> 614 615 Level: intermediate 616 617 SNESNGMRESSelectTypes: 618 + SNES_NGMRES_SELECT_NONE - choose the combined solution all the time 619 . SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria 620 - SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination 621 622 Notes: 623 The default line search used is the L2 line search and it requires two additional function evaluations. 624 625 .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch 626 @*/ 627 628 PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype) { 629 PetscErrorCode ierr; 630 PetscFunctionBegin; 631 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 632 ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr); 633 PetscFunctionReturn(0); 634 } 635 636 637 EXTERN_C_BEGIN 638 #undef __FUNCT__ 639 #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES" 640 641 PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype) { 642 SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 643 PetscFunctionBegin; 644 ngmres->select_type = stype; 645 PetscFunctionReturn(0); 646 } 647 648 #undef __FUNCT__ 649 #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES" 650 651 PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype) { 652 SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 653 PetscFunctionBegin; 654 ngmres->restart_type = rtype; 655 PetscFunctionReturn(0); 656 } 657 EXTERN_C_END 658 659 660 /*MC 661 SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 662 663 Level: beginner 664 665 Options Database: 666 + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 667 + -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 668 . -snes_ngmres_anderson - Use Anderson mixing NGMRES variant which combines candidate solutions instead of actual solutions 669 . -snes_ngmres_m - Number of stored previous solutions and residuals 670 . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 671 . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 672 . -snes_ngmres_gammaC - Residual tolerance for restart 673 . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 674 . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 675 . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 676 . -snes_linesearch_type <basic,basicnonorms,quadratic,critical> - Line search type used for the default smoother 677 - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 678 679 Notes: 680 681 The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 682 optimization problem at each iteration. 683 684 References: 685 686 "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio, 687 SIAM Journal on Scientific Computing, 21(5), 2000. 688 689 This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations. 690 J. Assoc. Comput. Mach., 12:547–560, 1965." 691 692 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 693 M*/ 694 695 EXTERN_C_BEGIN 696 #undef __FUNCT__ 697 #define __FUNCT__ "SNESCreate_NGMRES" 698 PetscErrorCode SNESCreate_NGMRES(SNES snes) 699 { 700 SNES_NGMRES *ngmres; 701 PetscErrorCode ierr; 702 703 PetscFunctionBegin; 704 snes->ops->destroy = SNESDestroy_NGMRES; 705 snes->ops->setup = SNESSetUp_NGMRES; 706 snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 707 snes->ops->view = SNESView_NGMRES; 708 snes->ops->solve = SNESSolve_NGMRES; 709 snes->ops->reset = SNESReset_NGMRES; 710 711 snes->usespc = PETSC_TRUE; 712 snes->usesksp = PETSC_FALSE; 713 714 ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr); 715 snes->data = (void*) ngmres; 716 ngmres->msize = 30; 717 718 if (!snes->tolerancesset) { 719 snes->max_funcs = 30000; 720 snes->max_its = 10000; 721 } 722 723 ngmres->anderson = PETSC_FALSE; 724 725 ngmres->additive_linesearch = PETSC_NULL; 726 727 ngmres->restart_it = 2; 728 ngmres->restart_periodic = 30; 729 ngmres->gammaA = 2.0; 730 ngmres->gammaC = 2.0; 731 ngmres->deltaB = 0.9; 732 ngmres->epsilonB = 0.1; 733 734 ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 735 ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 736 737 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetSelectType_C","SNESNGMRESSetSelectType_NGMRES", SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr); 738 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetRestartType_C","SNESNGMRESSetRestartType_NGMRES", SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr); 739 740 PetscFunctionReturn(0); 741 } 742 EXTERN_C_END 743