1 #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 2 #include <petscblaslapack.h> 3 4 const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0}; 5 const char *const 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,xnorm,ynorm; 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(((PetscObject)snes)->comm, 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(((PetscObject)snes)->comm, 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(((PetscObject)snes)->comm,PETSC_ERR_LIB,"Bad argument to GELSS"); 350 if (ngmres->info > 0) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_LIB,"SVD failed to converge"); 351 #endif 352 } 353 354 for (i=0;i<l;i++) { 355 if (PetscIsInfOrNanScalar(beta[i])) { 356 SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_LIB,"SVD generated inconsistent output"); 357 } 358 } 359 360 alph_total = 0.; 361 for (i = 0; i < l; i++) { 362 alph_total += beta[i]; 363 } 364 365 ierr = VecCopy(XM, XA);CHKERRQ(ierr); 366 ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr); 367 368 ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr); 369 370 /* check the validity of the step */ 371 ierr = VecCopy(XA,Y);CHKERRQ(ierr); 372 ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr); 373 ierr = SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);CHKERRQ(ierr); 374 ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr); 375 376 /* differences for selection and restart */ 377 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 378 if (ngmres->singlereduction) { 379 dminnorm = -1.0; 380 ierr=VecCopy(XA, D);CHKERRQ(ierr); 381 ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr); 382 for(i=0;i<l;i++) { 383 ierr=VecAXPY(Xdot[i],-1.0,XA);CHKERRQ(ierr); 384 } 385 ierr = VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 386 ierr = VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr); 387 for (i=0;i<l;i++) { 388 ierr = VecNormBegin(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr); 389 } 390 ierr = VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 391 ierr = VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr); 392 for (i=0;i<l;i++) { 393 ierr = VecNormEnd(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr); 394 } 395 for(i=0;i<l;i++) { 396 dcurnorm = ngmres->xnorms[i]; 397 if ((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm; 398 ierr=VecAXPY(Xdot[i],1.0,XA);CHKERRQ(ierr); 399 } 400 } else { 401 ierr=VecCopy(XA, D);CHKERRQ(ierr); 402 ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr); 403 ierr=VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr); 404 ierr=VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 405 ierr=VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr); 406 ierr=VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 407 dminnorm = -1.0; 408 for(i=0;i<l;i++) { 409 ierr=VecCopy(XA, D);CHKERRQ(ierr); 410 ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr); 411 ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr); 412 if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm; 413 } 414 } 415 } else { 416 ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 417 } 418 if (PetscIsInfOrNanReal(fAnorm)) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation"); 419 /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 420 if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 421 /* X = X + \lambda(XA - X) */ 422 if (ngmres->monitor) { 423 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 424 } 425 ierr = VecCopy(FM, F);CHKERRQ(ierr); 426 ierr = VecCopy(XM, X);CHKERRQ(ierr); 427 ierr = VecCopy(XA, Y);CHKERRQ(ierr); 428 ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr); 429 fnorm = fMnorm; 430 ierr = SNESLineSearchApply(ngmres->additive_linesearch,X,F,&fnorm,Y);CHKERRQ(ierr); 431 ierr = SNESLineSearchGetSuccess(ngmres->additive_linesearch, &lssucceed);CHKERRQ(ierr); 432 if (!lssucceed) { 433 if (++snes->numFailures >= snes->maxFailures) { 434 snes->reason = SNES_DIVERGED_LINE_SEARCH; 435 PetscFunctionReturn(0); 436 } 437 } 438 if (ngmres->monitor) { 439 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", fnorm);CHKERRQ(ierr); 440 } 441 } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 442 selectA = PETSC_TRUE; 443 /* Conditions for choosing the accelerated answer */ 444 /* Criterion A -- the norm of the function isn't increased above the minimum by too much */ 445 if (fAnorm >= ngmres->gammaA*fminnorm) { 446 selectA = PETSC_FALSE; 447 } 448 /* Criterion B -- the choice of x^A isn't too close to some other choice */ 449 if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) { 450 } else { 451 selectA=PETSC_FALSE; 452 } 453 if (selectA) { 454 if (ngmres->monitor) { 455 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 456 } 457 /* copy it over */ 458 fnorm = fAnorm; 459 nu = fnorm*fnorm; 460 ierr = VecCopy(FA, F);CHKERRQ(ierr); 461 ierr = VecCopy(XA, X);CHKERRQ(ierr); 462 } else { 463 if (ngmres->monitor) { 464 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 465 } 466 fnorm = fMnorm; 467 nu = fnorm*fnorm; 468 ierr = VecCopy(XM, Y);CHKERRQ(ierr); 469 ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr); 470 ierr = VecCopy(FM, F);CHKERRQ(ierr); 471 ierr = VecCopy(XM, X);CHKERRQ(ierr); 472 } 473 } else { /* none */ 474 fnorm = fAnorm; 475 nu = fnorm*fnorm; 476 ierr = VecCopy(FA, F);CHKERRQ(ierr); 477 ierr = VecCopy(XA, X);CHKERRQ(ierr); 478 } 479 480 selectRestart = PETSC_FALSE; 481 if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { 482 /* difference stagnation restart */ 483 if((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm))) { 484 if (ngmres->monitor) { 485 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr); 486 } 487 selectRestart = PETSC_TRUE; 488 } 489 /* residual stagnation restart */ 490 if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) { 491 if (ngmres->monitor) { 492 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", PetscSqrtReal(fAnorm), ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr); 493 } 494 selectRestart = PETSC_TRUE; 495 } 496 /* if the restart conditions persist for more than restart_it iterations, restart. */ 497 if (selectRestart) { 498 restart_count++; 499 } else { 500 restart_count = 0; 501 } 502 } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { 503 if (k_restart > ngmres->restart_periodic) { 504 if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %D iterations\n", k_restart);CHKERRQ(ierr); 505 restart_count = ngmres->restart_it; 506 } 507 } 508 /* restart after restart conditions have persisted for a fixed number of iterations */ 509 if (restart_count >= ngmres->restart_it) { 510 if (ngmres->monitor){ 511 ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr); 512 } 513 restart_count = 0; 514 k_restart = 1; 515 l = 1; 516 /* q_{00} = nu */ 517 if (ngmres->anderson) { 518 ngmres->fnorms[0] = fMnorm; 519 nu = fMnorm*fMnorm; 520 Q(0,0) = nu; 521 /* Fdot[0] = F */ 522 ierr = VecCopy(XM, Xdot[0]);CHKERRQ(ierr); 523 ierr = VecCopy(FM, Fdot[0]);CHKERRQ(ierr); 524 } else { 525 ngmres->fnorms[0] = fnorm; 526 nu = fnorm*fnorm; 527 Q(0,0) = nu; 528 /* Fdot[0] = F */ 529 ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr); 530 ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr); 531 } 532 } else { 533 /* select the current size of the subspace */ 534 if (l < ngmres->msize) l++; 535 k_restart++; 536 /* place the current entry in the list of previous entries */ 537 if (ngmres->anderson) { 538 ierr = VecCopy(FM, Fdot[ivec]);CHKERRQ(ierr); 539 ierr = VecCopy(XM, Xdot[ivec]);CHKERRQ(ierr); 540 ngmres->fnorms[ivec] = fMnorm; 541 if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of FM */ 542 xi[ivec] = fMnorm*fMnorm; 543 for (i = 0; i < l; i++) { 544 Q(i, ivec) = xi[i]; 545 Q(ivec, i) = xi[i]; 546 } 547 } else { 548 ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr); 549 ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr); 550 ngmres->fnorms[ivec] = fnorm; 551 if (fminnorm > fnorm) fminnorm = fnorm; /* the minimum norm is now of FA */ 552 ierr = VecMDot(F, l, Fdot, xi);CHKERRQ(ierr); 553 for (i = 0; i < l; i++) { 554 Q(i, ivec) = xi[i]; 555 Q(ivec, i) = xi[i]; 556 } 557 } 558 } 559 560 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 561 snes->iter = k; 562 snes->norm = fnorm; 563 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 564 SNESLogConvHistory(snes, snes->norm, snes->iter); 565 ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr); 566 ierr = VecNormBegin(Y,NORM_2,&ynorm);CHKERRQ(ierr); 567 ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); 568 ierr = VecNormEnd(Y,NORM_2,&ynorm);CHKERRQ(ierr); 569 ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); 570 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 571 if (snes->reason) PetscFunctionReturn(0); 572 } 573 snes->reason = SNES_DIVERGED_MAX_IT; 574 PetscFunctionReturn(0); 575 } 576 577 #undef __FUNCT__ 578 #define __FUNCT__ "SNESNGMRESSetRestartType" 579 /*@ 580 SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES. 581 582 Logically Collective on SNES 583 584 Input Parameters: 585 + snes - the iterative context 586 - rtype - restart type 587 588 Options Database: 589 + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 590 - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 591 592 Level: intermediate 593 594 SNESNGMRESRestartTypes: 595 + SNES_NGMRES_RESTART_NONE - never restart 596 . SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria 597 - SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations 598 599 Notes: 600 The default line search used is the L2 line search and it requires two additional function evaluations. 601 602 .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch 603 @*/ 604 PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype) { 605 PetscErrorCode ierr; 606 PetscFunctionBegin; 607 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 608 ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr); 609 PetscFunctionReturn(0); 610 } 611 612 #undef __FUNCT__ 613 #define __FUNCT__ "SNESNGMRESSetSelectType" 614 /*@ 615 SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES. This determines how the candidate solution and 616 combined solution are used to create the next iterate. 617 618 Logically Collective on SNES 619 620 Input Parameters: 621 + snes - the iterative context 622 - stype - selection type 623 624 Options Database: 625 . -snes_ngmres_select_type<difference,none,linesearch> 626 627 Level: intermediate 628 629 SNESNGMRESSelectTypes: 630 + SNES_NGMRES_SELECT_NONE - choose the combined solution all the time 631 . SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria 632 - SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination 633 634 Notes: 635 The default line search used is the L2 line search and it requires two additional function evaluations. 636 637 .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch 638 @*/ 639 640 PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype) { 641 PetscErrorCode ierr; 642 PetscFunctionBegin; 643 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 644 ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr); 645 PetscFunctionReturn(0); 646 } 647 648 649 EXTERN_C_BEGIN 650 #undef __FUNCT__ 651 #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES" 652 653 PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype) { 654 SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 655 PetscFunctionBegin; 656 ngmres->select_type = stype; 657 PetscFunctionReturn(0); 658 } 659 660 #undef __FUNCT__ 661 #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES" 662 663 PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype) { 664 SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 665 PetscFunctionBegin; 666 ngmres->restart_type = rtype; 667 PetscFunctionReturn(0); 668 } 669 EXTERN_C_END 670 671 672 /*MC 673 SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 674 675 Level: beginner 676 677 Options Database: 678 + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 679 + -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 680 . -snes_ngmres_anderson - Use Anderson mixing NGMRES variant which combines candidate solutions instead of actual solutions 681 . -snes_ngmres_m - Number of stored previous solutions and residuals 682 . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 683 . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 684 . -snes_ngmres_gammaC - Residual tolerance for restart 685 . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 686 . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 687 . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 688 . -snes_linesearch_type <basic,basicnonorms,quadratic,critical> - Line search type used for the default smoother 689 - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 690 691 Notes: 692 693 The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 694 optimization problem at each iteration. 695 696 References: 697 698 "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio, 699 SIAM Journal on Scientific Computing, 21(5), 2000. 700 701 This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations. 702 J. Assoc. Comput. Mach., 12:547–560, 1965." 703 704 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 705 M*/ 706 707 EXTERN_C_BEGIN 708 #undef __FUNCT__ 709 #define __FUNCT__ "SNESCreate_NGMRES" 710 PetscErrorCode SNESCreate_NGMRES(SNES snes) 711 { 712 SNES_NGMRES *ngmres; 713 PetscErrorCode ierr; 714 715 PetscFunctionBegin; 716 snes->ops->destroy = SNESDestroy_NGMRES; 717 snes->ops->setup = SNESSetUp_NGMRES; 718 snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 719 snes->ops->view = SNESView_NGMRES; 720 snes->ops->solve = SNESSolve_NGMRES; 721 snes->ops->reset = SNESReset_NGMRES; 722 723 snes->usespc = PETSC_TRUE; 724 snes->usesksp = PETSC_FALSE; 725 726 ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr); 727 snes->data = (void*) ngmres; 728 ngmres->msize = 30; 729 730 if (!snes->tolerancesset) { 731 snes->max_funcs = 30000; 732 snes->max_its = 10000; 733 } 734 735 ngmres->anderson = PETSC_FALSE; 736 737 ngmres->additive_linesearch = PETSC_NULL; 738 739 ngmres->restart_it = 2; 740 ngmres->restart_periodic = 30; 741 ngmres->gammaA = 2.0; 742 ngmres->gammaC = 2.0; 743 ngmres->deltaB = 0.9; 744 ngmres->epsilonB = 0.1; 745 746 ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 747 ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 748 749 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetSelectType_C","SNESNGMRESSetSelectType_NGMRES", SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr); 750 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetRestartType_C","SNESNGMRESSetRestartType_NGMRES", SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr); 751 752 PetscFunctionReturn(0); 753 } 754 EXTERN_C_END 755