14b11644fSPeter Brune #include <private/snesimpl.h> 24b11644fSPeter Brune 388d374b2SPeter Brune typedef enum {SNES_QN_SEQUENTIAL, SNES_QN_COMPOSED} SNESQNCompositionType; 40ecc9e1dSPeter Brune typedef enum {SNES_QN_SHANNOSCALE, SNES_QN_LSSCALE, SNES_QN_JACOBIANSCALE} SNESQNScalingType; 56bf1b2e5SPeter Brune 64b11644fSPeter Brune typedef struct { 74b11644fSPeter Brune Vec *dX; /* The change in X */ 86bf1b2e5SPeter Brune Vec *dF; /* The change in F */ 94b11644fSPeter Brune PetscInt m; /* the number of kept previous steps */ 10bd052dfeSPeter Brune PetscScalar *alpha; 11bd052dfeSPeter Brune PetscScalar *beta; 12bd052dfeSPeter Brune PetscScalar *rho; 1344f7e39eSPeter Brune PetscViewer monitor; 146bf1b2e5SPeter Brune PetscReal powell_gamma; /* Powell angle restart condition */ 156bf1b2e5SPeter Brune PetscReal powell_downhill; /* Powell descent restart condition */ 16b21d5a53SPeter Brune PetscReal scaling; /* scaling of H0 */ 170ecc9e1dSPeter Brune PetscInt n_restart; /* the maximum iterations between restart */ 1888d374b2SPeter Brune 1988d374b2SPeter Brune SNESQNCompositionType compositiontype; /* determine if the composition is done sequentially or as a composition */ 200ecc9e1dSPeter Brune SNESQNScalingType scalingtype; /* determine if the composition is done sequentially or as a composition */ 2188d374b2SPeter Brune 229f83bee8SJed Brown } SNES_QN; 234b11644fSPeter Brune 244b11644fSPeter Brune #undef __FUNCT__ 254b11644fSPeter Brune #define __FUNCT__ "LBGFSApplyJinv_Private" 263af51624SPeter Brune PetscErrorCode LBGFSApplyJinv_Private(SNES snes, PetscInt it, Vec D, Vec Y) { 274b11644fSPeter Brune 284b11644fSPeter Brune PetscErrorCode ierr; 294b11644fSPeter Brune 309f83bee8SJed Brown SNES_QN *qn = (SNES_QN*)snes->data; 314b11644fSPeter Brune 320ecc9e1dSPeter Brune Vec Yin = snes->work[0]; 330ecc9e1dSPeter Brune 344b11644fSPeter Brune Vec *dX = qn->dX; 356bf1b2e5SPeter Brune Vec *dF = qn->dF; 364b11644fSPeter Brune 37bd052dfeSPeter Brune PetscScalar *alpha = qn->alpha; 38bd052dfeSPeter Brune PetscScalar *beta = qn->beta; 39bd052dfeSPeter Brune PetscScalar *rho = qn->rho; 40bd052dfeSPeter Brune 410ecc9e1dSPeter Brune /* ksp thing for jacobian scaling */ 420ecc9e1dSPeter Brune KSPConvergedReason kspreason; 430ecc9e1dSPeter Brune MatStructure flg = DIFFERENT_NONZERO_PATTERN; 440ecc9e1dSPeter Brune 450ecc9e1dSPeter Brune PetscInt k, i, lits; 464b11644fSPeter Brune PetscInt m = qn->m; 474b11644fSPeter Brune PetscScalar t; 484b11644fSPeter Brune PetscInt l = m; 494b11644fSPeter Brune 504b11644fSPeter Brune PetscFunctionBegin; 514b11644fSPeter Brune 523af51624SPeter Brune ierr = VecCopy(D, Y);CHKERRQ(ierr); 534b11644fSPeter Brune 545ba6227bSPeter Brune if (it < m) l = it; 554b11644fSPeter Brune 564b11644fSPeter Brune /* outward recursion starting at iteration k's update and working back */ 574b11644fSPeter Brune for (i = 0; i < l; i++) { 58b21d5a53SPeter Brune k = (it - i - 1) % l; 593af51624SPeter Brune ierr = VecDot(dX[k], Y, &t);CHKERRQ(ierr); 60bd052dfeSPeter Brune alpha[k] = t*rho[k]; 6144f7e39eSPeter Brune if (qn->monitor) { 623af51624SPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 635ba6227bSPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); 643af51624SPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 6544f7e39eSPeter Brune } 666bf1b2e5SPeter Brune ierr = VecAXPY(Y, -alpha[k], dF[k]);CHKERRQ(ierr); 674b11644fSPeter Brune } 684b11644fSPeter Brune 690ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 700ecc9e1dSPeter Brune ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 710ecc9e1dSPeter Brune ierr = SNES_KSPSolve(snes,snes->ksp,Y,Yin);CHKERRQ(ierr); 720ecc9e1dSPeter Brune ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 730ecc9e1dSPeter Brune if (kspreason < 0) { 740ecc9e1dSPeter Brune if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 750ecc9e1dSPeter Brune ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 760ecc9e1dSPeter Brune snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 770ecc9e1dSPeter Brune PetscFunctionReturn(0); 780ecc9e1dSPeter Brune } 790ecc9e1dSPeter Brune } 800ecc9e1dSPeter Brune ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 810ecc9e1dSPeter Brune snes->linear_its += lits; 820ecc9e1dSPeter Brune ierr = VecCopy(Yin, Y);CHKERRQ(ierr); 830ecc9e1dSPeter Brune } else { 84b21d5a53SPeter Brune ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); 850ecc9e1dSPeter Brune } 864b11644fSPeter Brune /* inward recursion starting at the first update and working forward */ 87bd052dfeSPeter Brune for (i = 0; i < l; i++) { 88b21d5a53SPeter Brune k = (it + i - l) % l; 896bf1b2e5SPeter Brune ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); 904b11644fSPeter Brune beta[k] = rho[k]*t; 913af51624SPeter Brune ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]); 9244f7e39eSPeter Brune if (qn->monitor) { 933af51624SPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 945ba6227bSPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); 953af51624SPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 9644f7e39eSPeter Brune } 974b11644fSPeter Brune } 984b11644fSPeter Brune PetscFunctionReturn(0); 994b11644fSPeter Brune } 1004b11644fSPeter Brune 1014b11644fSPeter Brune #undef __FUNCT__ 1024b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN" 1034b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes) 1044b11644fSPeter Brune { 1054b11644fSPeter Brune 1064b11644fSPeter Brune PetscErrorCode ierr; 1079f83bee8SJed Brown SNES_QN *qn = (SNES_QN*) snes->data; 1084b11644fSPeter Brune 10915f5eeeaSPeter Brune Vec X, Xold; 1103af51624SPeter Brune Vec F, G, B; 11188d374b2SPeter Brune Vec W, Y, FPC, D, Dold; 1123af51624SPeter Brune SNESConvergedReason reason; 1135ba6227bSPeter Brune PetscInt i, i_r, k; 1144b11644fSPeter Brune 1159f3a0142SPeter Brune PetscReal fnorm, xnorm = 0, ynorm, gnorm; 1164b11644fSPeter Brune PetscInt m = qn->m; 11705b53524SPeter Brune PetscBool lssucceed, changed; 1184b11644fSPeter Brune 119bd052dfeSPeter Brune PetscScalar rhosc; 120bd052dfeSPeter Brune 121bd052dfeSPeter Brune Vec *dX = qn->dX; 1226bf1b2e5SPeter Brune Vec *dF = qn->dF; 123bd052dfeSPeter Brune PetscScalar *rho = qn->rho; 12488d374b2SPeter Brune PetscScalar DolddotD, DolddotDold, DdotD, YdotD, a; 1254b11644fSPeter Brune 1260ecc9e1dSPeter Brune MatStructure flg = DIFFERENT_NONZERO_PATTERN; 1270ecc9e1dSPeter Brune 1284b11644fSPeter Brune /* basically just a regular newton's method except for the application of the jacobian */ 1294b11644fSPeter Brune PetscFunctionBegin; 1304b11644fSPeter Brune 1319f3a0142SPeter Brune X = snes->vec_sol; /* solution vector */ 1329f3a0142SPeter Brune F = snes->vec_func; /* residual vector */ 1333af51624SPeter Brune Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 1343af51624SPeter Brune B = snes->vec_rhs; 13570d3b23bSPeter Brune G = snes->work[0]; 13670d3b23bSPeter Brune W = snes->work[1]; 13770d3b23bSPeter Brune Xold = snes->work[2]; 1383af51624SPeter Brune 1393af51624SPeter Brune /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ 14088d374b2SPeter Brune D = snes->work[3]; 14188d374b2SPeter Brune Dold = snes->work[4]; 1424b11644fSPeter Brune 1434b11644fSPeter Brune snes->reason = SNES_CONVERGED_ITERATING; 1444b11644fSPeter Brune 1454b11644fSPeter Brune ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1464b11644fSPeter Brune snes->iter = 0; 1474b11644fSPeter Brune snes->norm = 0.; 1484b11644fSPeter Brune ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 14915f5eeeaSPeter Brune ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 1504b11644fSPeter Brune if (snes->domainerror) { 1514b11644fSPeter Brune snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 1524b11644fSPeter Brune PetscFunctionReturn(0); 1534b11644fSPeter Brune } 15415f5eeeaSPeter Brune ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1554b11644fSPeter Brune if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 1564b11644fSPeter Brune ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1574b11644fSPeter Brune snes->norm = fnorm; 1584b11644fSPeter Brune ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1594b11644fSPeter Brune SNESLogConvHistory(snes,fnorm,0); 1604b11644fSPeter Brune ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 1614b11644fSPeter Brune 1624b11644fSPeter Brune /* set parameter for default relative tolerance convergence test */ 1634b11644fSPeter Brune snes->ttol = fnorm*snes->rtol; 1644b11644fSPeter Brune /* test convergence */ 1654b11644fSPeter Brune ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 1664b11644fSPeter Brune if (snes->reason) PetscFunctionReturn(0); 16770d3b23bSPeter Brune 16888d374b2SPeter Brune /* composed solve -- either sequential or composed */ 16988d374b2SPeter Brune if (snes->pc) { 17088d374b2SPeter Brune if (qn->compositiontype == SNES_QN_SEQUENTIAL) { 17188d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 17288d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 17388d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 17488d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 17588d374b2SPeter Brune PetscFunctionReturn(0); 17688d374b2SPeter Brune } 17788d374b2SPeter Brune ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 17888d374b2SPeter Brune ierr = VecCopy(FPC, F);CHKERRQ(ierr); 17988d374b2SPeter Brune ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); 1806bf1b2e5SPeter Brune ierr = VecCopy(F, Y);CHKERRQ(ierr); 18188d374b2SPeter Brune } else { 18288d374b2SPeter Brune ierr = VecCopy(X, Y);CHKERRQ(ierr); 18388d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, Y);CHKERRQ(ierr); 18488d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 18588d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 18688d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 18788d374b2SPeter Brune PetscFunctionReturn(0); 18888d374b2SPeter Brune } 18988d374b2SPeter Brune ierr = VecAYPX(Y,-1.0,X);CHKERRQ(ierr); 19088d374b2SPeter Brune } 19188d374b2SPeter Brune } else { 19288d374b2SPeter Brune ierr = VecCopy(F, Y);CHKERRQ(ierr); 19388d374b2SPeter Brune } 19488d374b2SPeter Brune ierr = VecCopy(Y, D);CHKERRQ(ierr); 1953af51624SPeter Brune 196*f8e15203SPeter Brune /* scale the initial update */ 1970ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 1980ecc9e1dSPeter Brune ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 1990ecc9e1dSPeter Brune } 2000ecc9e1dSPeter Brune 2015ba6227bSPeter Brune for(i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 202*f8e15203SPeter Brune ierr = LBGFSApplyJinv_Private(snes, i_r, D, Y);CHKERRQ(ierr); 20370d3b23bSPeter Brune /* line search for lambda */ 20470d3b23bSPeter Brune ynorm = 1; gnorm = fnorm; 20588d374b2SPeter Brune ierr = VecCopy(D, Dold);CHKERRQ(ierr); 20615f5eeeaSPeter Brune ierr = VecCopy(X, Xold);CHKERRQ(ierr); 20705b53524SPeter Brune ierr = SNESLineSearchPreCheckApply(snes,X,Y,&changed);CHKERRQ(ierr); 20805b53524SPeter Brune ierr = SNESLineSearchApply(snes,X,F,Y,fnorm,xnorm,W,G,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 2099f3a0142SPeter Brune if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 2109f3a0142SPeter Brune if (snes->domainerror) { 2119f3a0142SPeter Brune snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 2129f3a0142SPeter Brune PetscFunctionReturn(0); 2139f3a0142SPeter Brune } 2149f3a0142SPeter Brune if (!lssucceed) { 2159f3a0142SPeter Brune if (++snes->numFailures >= snes->maxFailures) { 2169f3a0142SPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 2179f3a0142SPeter Brune break; 2189f3a0142SPeter Brune } 2199f3a0142SPeter Brune } 2200ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_LSSCALE) { 2210ecc9e1dSPeter Brune qn->scaling = ynorm; 2220ecc9e1dSPeter Brune } 2239f3a0142SPeter Brune /* Update function and solution vectors */ 2249f3a0142SPeter Brune fnorm = gnorm; 2259f3a0142SPeter Brune ierr = VecCopy(G,F);CHKERRQ(ierr); 22615f5eeeaSPeter Brune ierr = VecCopy(W,X);CHKERRQ(ierr); 2273af51624SPeter Brune 22888d374b2SPeter Brune /* convergence monitoring */ 229b21d5a53SPeter Brune ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); 230b21d5a53SPeter Brune 231360c497dSPeter Brune ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 232360c497dSPeter Brune ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); 233360c497dSPeter Brune 2348409ca45SMatthew G Knepley SNESLogConvHistory(snes,snes->norm,snes->iter); 2358409ca45SMatthew G Knepley ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 2364b11644fSPeter Brune /* set parameter for default relative tolerance convergence test */ 2375ba6227bSPeter Brune ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 2384b11644fSPeter Brune if (snes->reason) PetscFunctionReturn(0); 2394b11644fSPeter Brune 24088d374b2SPeter Brune 24188d374b2SPeter Brune if (snes->pc) { 24288d374b2SPeter Brune if (qn->compositiontype == SNES_QN_SEQUENTIAL) { 24388d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 24488d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 24588d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 24688d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 24788d374b2SPeter Brune PetscFunctionReturn(0); 24888d374b2SPeter Brune } 24988d374b2SPeter Brune ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 25088d374b2SPeter Brune ierr = VecCopy(FPC, F);CHKERRQ(ierr); 25188d374b2SPeter Brune ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); 25288d374b2SPeter Brune ierr = VecCopy(F, D);CHKERRQ(ierr); 25388d374b2SPeter Brune } else { 25488d374b2SPeter Brune ierr = VecCopy(X, D);CHKERRQ(ierr); 25588d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, D);CHKERRQ(ierr); 25688d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 25788d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 25888d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 25988d374b2SPeter Brune PetscFunctionReturn(0); 26088d374b2SPeter Brune } 26188d374b2SPeter Brune ierr = VecAYPX(D,-1.0,X);CHKERRQ(ierr); 26288d374b2SPeter Brune } 26388d374b2SPeter Brune } else { 26488d374b2SPeter Brune ierr = VecCopy(F, D);CHKERRQ(ierr); 26588d374b2SPeter Brune } 26688d374b2SPeter Brune 2676bf1b2e5SPeter Brune /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 26888d374b2SPeter Brune ierr = VecDot(Dold, Dold, &DolddotDold);CHKERRQ(ierr); 26988d374b2SPeter Brune ierr = VecDot(Dold, D, &DolddotD);CHKERRQ(ierr); 27088d374b2SPeter Brune ierr = VecDot(D, D, &DdotD);CHKERRQ(ierr); 27188d374b2SPeter Brune ierr = VecDot(Y, D, &YdotD);CHKERRQ(ierr); 2720ecc9e1dSPeter Brune if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold)) || (i_r > qn->n_restart - 1 && qn->n_restart > 0)) { 2735ba6227bSPeter Brune if (qn->monitor) { 2745ba6227bSPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 2750ecc9e1dSPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "restart! |%14.12e| > %4.2f*|%14.12e| or i_r = %d\n", k, PetscRealPart(DolddotD), qn->powell_gamma, PetscRealPart(DolddotDold), i_r);CHKERRQ(ierr); 2765ba6227bSPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 2775ba6227bSPeter Brune } 2785ba6227bSPeter Brune i_r = -1; 2795ba6227bSPeter Brune /* general purpose update */ 2805ba6227bSPeter Brune if (snes->ops->update) { 2815ba6227bSPeter Brune ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 2825ba6227bSPeter Brune } 2830ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 2840ecc9e1dSPeter Brune ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 2850ecc9e1dSPeter Brune } 2865ba6227bSPeter Brune } else { 287bd052dfeSPeter Brune /* set the differences */ 2885ba6227bSPeter Brune k = i_r % m; 28988d374b2SPeter Brune ierr = VecCopy(D, dF[k]);CHKERRQ(ierr); 29088d374b2SPeter Brune ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr); 29115f5eeeaSPeter Brune ierr = VecCopy(X, dX[k]);CHKERRQ(ierr); 29215f5eeeaSPeter Brune ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr); 2936bf1b2e5SPeter Brune ierr = VecDot(dX[k], dF[k], &rhosc);CHKERRQ(ierr); 2946bf1b2e5SPeter Brune 2956bf1b2e5SPeter Brune /* set scaling to be shanno scaling */ 296bd052dfeSPeter Brune rho[k] = 1. / rhosc; 2970ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_SHANNOSCALE) { 2986bf1b2e5SPeter Brune ierr = VecDot(dF[k], dF[k], &a);CHKERRQ(ierr); 2991b2f85ebSPeter Brune qn->scaling = PetscRealPart(rhosc) / PetscRealPart(a); 3000ecc9e1dSPeter Brune } 30170d3b23bSPeter Brune /* general purpose update */ 30270d3b23bSPeter Brune if (snes->ops->update) { 30370d3b23bSPeter Brune ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 30470d3b23bSPeter Brune } 3055ba6227bSPeter Brune } 3064b11644fSPeter Brune } 3074b11644fSPeter Brune if (i == snes->max_its) { 3084b11644fSPeter Brune ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 3094b11644fSPeter Brune if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 3104b11644fSPeter Brune } 3114b11644fSPeter Brune PetscFunctionReturn(0); 3124b11644fSPeter Brune } 3134b11644fSPeter Brune 3144b11644fSPeter Brune 3154b11644fSPeter Brune #undef __FUNCT__ 3164b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN" 3174b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes) 3184b11644fSPeter Brune { 3199f83bee8SJed Brown SNES_QN *qn = (SNES_QN*)snes->data; 3204b11644fSPeter Brune PetscErrorCode ierr; 3214b11644fSPeter Brune PetscFunctionBegin; 3224b11644fSPeter Brune ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->dX);CHKERRQ(ierr); 3236bf1b2e5SPeter Brune ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->dF);CHKERRQ(ierr); 324bd052dfeSPeter Brune ierr = PetscMalloc3(qn->m, PetscScalar, &qn->alpha, qn->m, PetscScalar, &qn->beta, qn->m, PetscScalar, &qn->rho);CHKERRQ(ierr); 32588d374b2SPeter Brune ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr); 3260ecc9e1dSPeter Brune 3274b11644fSPeter Brune PetscFunctionReturn(0); 3284b11644fSPeter Brune } 3294b11644fSPeter Brune 3304b11644fSPeter Brune #undef __FUNCT__ 3314b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN" 3324b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes) 3334b11644fSPeter Brune { 3344b11644fSPeter Brune PetscErrorCode ierr; 3359f83bee8SJed Brown SNES_QN *qn; 3364b11644fSPeter Brune PetscFunctionBegin; 3374b11644fSPeter Brune if (snes->data) { 3389f83bee8SJed Brown qn = (SNES_QN*)snes->data; 3394b11644fSPeter Brune if (qn->dX) { 3404b11644fSPeter Brune ierr = VecDestroyVecs(qn->m, &qn->dX);CHKERRQ(ierr); 3414b11644fSPeter Brune } 3426bf1b2e5SPeter Brune if (qn->dF) { 3436bf1b2e5SPeter Brune ierr = VecDestroyVecs(qn->m, &qn->dF);CHKERRQ(ierr); 3444b11644fSPeter Brune } 345bd052dfeSPeter Brune ierr = PetscFree3(qn->alpha, qn->beta, qn->rho);CHKERRQ(ierr); 3464b11644fSPeter Brune } 3474b11644fSPeter Brune PetscFunctionReturn(0); 3484b11644fSPeter Brune } 3494b11644fSPeter Brune 3504b11644fSPeter Brune #undef __FUNCT__ 3514b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN" 3524b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes) 3534b11644fSPeter Brune { 3544b11644fSPeter Brune PetscErrorCode ierr; 3554b11644fSPeter Brune PetscFunctionBegin; 3564b11644fSPeter Brune ierr = SNESReset_QN(snes);CHKERRQ(ierr); 3574b11644fSPeter Brune ierr = PetscFree(snes->data);CHKERRQ(ierr); 3589c05af5eSJed Brown ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"","",PETSC_NULL);CHKERRQ(ierr); 3594b11644fSPeter Brune PetscFunctionReturn(0); 3604b11644fSPeter Brune } 3614b11644fSPeter Brune 3624b11644fSPeter Brune #undef __FUNCT__ 3634b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN" 3644b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes) 3654b11644fSPeter Brune { 3664b11644fSPeter Brune 3674b11644fSPeter Brune PetscErrorCode ierr; 3689f83bee8SJed Brown SNES_QN *qn; 3695b4627e8SPeter Brune const char *compositions[] = {"sequential", "composed"}; 3700ecc9e1dSPeter Brune const char *scalings[] = {"shanno", "ls", "jacobian"}; 37188d374b2SPeter Brune PetscInt indx = 0; 37288d374b2SPeter Brune PetscBool flg; 37344f7e39eSPeter Brune PetscBool monflg = PETSC_FALSE; 3744b11644fSPeter Brune PetscFunctionBegin; 3754b11644fSPeter Brune 3769f83bee8SJed Brown qn = (SNES_QN*)snes->data; 3774b11644fSPeter Brune 3784b11644fSPeter Brune ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr); 3795b4627e8SPeter Brune ierr = PetscOptionsInt("-snes_qn_m", "Number of past states saved for L-BFGS methods", "SNESQN", qn->m, &qn->m, PETSC_NULL);CHKERRQ(ierr); 3800ecc9e1dSPeter Brune ierr = PetscOptionsInt("-snes_qn_restart", "Maximum number of iterations between restarts", "SNESQN", qn->n_restart, &qn->n_restart, PETSC_NULL);CHKERRQ(ierr); 3815b4627e8SPeter Brune ierr = PetscOptionsReal("-snes_qn_powell_gamma", "Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, PETSC_NULL);CHKERRQ(ierr); 3825b4627e8SPeter Brune ierr = PetscOptionsReal("-snes_qn_powell_downhill", "Powell descent tolerance", "SNESQN", qn->powell_downhill, &qn->powell_downhill, PETSC_NULL);CHKERRQ(ierr); 3835b4627e8SPeter Brune ierr = PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", monflg, &monflg, PETSC_NULL);CHKERRQ(ierr); 3845b4627e8SPeter Brune ierr = PetscOptionsEList("-snes_qn_composition", "Composition type", "SNESQN",compositions,2,"sequential",&indx,&flg);CHKERRQ(ierr); 38588d374b2SPeter Brune if (flg) { 38688d374b2SPeter Brune switch (indx) { 3875b4627e8SPeter Brune case 0: qn->compositiontype = SNES_QN_SEQUENTIAL; 3885b4627e8SPeter Brune break; 3895b4627e8SPeter Brune case 1: qn->compositiontype = SNES_QN_COMPOSED; 3905b4627e8SPeter Brune break; 39188d374b2SPeter Brune } 39288d374b2SPeter Brune } 3930ecc9e1dSPeter Brune ierr = PetscOptionsEList("-snes_qn_scaling", "Scaling type", "SNESQN",scalings,3,"shanno",&indx,&flg);CHKERRQ(ierr); 3940ecc9e1dSPeter Brune if (flg) { 3950ecc9e1dSPeter Brune switch (indx) { 3960ecc9e1dSPeter Brune case 0: qn->scalingtype = SNES_QN_SHANNOSCALE; 3970ecc9e1dSPeter Brune break; 3980ecc9e1dSPeter Brune case 1: qn->scalingtype = SNES_QN_LSSCALE; 3990ecc9e1dSPeter Brune break; 4000ecc9e1dSPeter Brune case 2: qn->scalingtype = SNES_QN_JACOBIANSCALE; 4010ecc9e1dSPeter Brune snes->usesksp = PETSC_TRUE; 4020ecc9e1dSPeter Brune break; 4030ecc9e1dSPeter Brune } 4040ecc9e1dSPeter Brune } 4050ecc9e1dSPeter Brune 4064b11644fSPeter Brune ierr = PetscOptionsTail();CHKERRQ(ierr); 40744f7e39eSPeter Brune if (monflg) { 40844f7e39eSPeter Brune qn->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 40944f7e39eSPeter Brune } 4104b11644fSPeter Brune PetscFunctionReturn(0); 4114b11644fSPeter Brune } 4124b11644fSPeter Brune 41392c02d66SPeter Brune EXTERN_C_BEGIN 41492c02d66SPeter Brune #undef __FUNCT__ 41592c02d66SPeter Brune #define __FUNCT__ "SNESLineSearchSetType_QN" 41692c02d66SPeter Brune PetscErrorCode SNESLineSearchSetType_QN(SNES snes, SNESLineSearchType type) 41792c02d66SPeter Brune { 41892c02d66SPeter Brune PetscErrorCode ierr; 41992c02d66SPeter Brune PetscFunctionBegin; 42092c02d66SPeter Brune 42192c02d66SPeter Brune switch (type) { 42292c02d66SPeter Brune case SNES_LS_BASIC: 42392c02d66SPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr); 42492c02d66SPeter Brune break; 42592c02d66SPeter Brune case SNES_LS_BASIC_NONORMS: 42692c02d66SPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 42792c02d66SPeter Brune break; 42892c02d66SPeter Brune case SNES_LS_QUADRATIC: 429af60355fSPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr); 43092c02d66SPeter Brune break; 431f3aaf736SPeter Brune case SNES_LS_CRITICAL: 432f3aaf736SPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchCriticalSecant,PETSC_NULL);CHKERRQ(ierr); 433cf9edfecSPeter Brune break; 43492c02d66SPeter Brune default: 43592c02d66SPeter Brune SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type"); 43692c02d66SPeter Brune break; 43792c02d66SPeter Brune } 43892c02d66SPeter Brune snes->ls_type = type; 43992c02d66SPeter Brune PetscFunctionReturn(0); 44092c02d66SPeter Brune } 44192c02d66SPeter Brune EXTERN_C_END 44292c02d66SPeter Brune 44392c02d66SPeter Brune 4444b11644fSPeter Brune /* -------------------------------------------------------------------------- */ 4454b11644fSPeter Brune /*MC 4464b11644fSPeter Brune SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems. 4474b11644fSPeter Brune 4486cc8130cSPeter Brune Options Database: 4496cc8130cSPeter Brune 4506cc8130cSPeter Brune + -snes_qn_m - Number of past states saved for the L-Broyden methods. 4511867fe5bSPeter Brune . -snes_qn_powell_angle - Angle condition for restart. 4521867fe5bSPeter Brune . -snes_qn_powell_descent - Descent condition for restart. 4531867fe5bSPeter Brune . -snes_qn_composition <sequential, composed>- Type of composition. 454f3aaf736SPeter Brune . -snes_ls <basic, basicnonorms, quadratic, critical> - Type of line search. 45544f7e39eSPeter Brune - -snes_qn_monitor - Monitors the quasi-newton jacobian. 4566cc8130cSPeter Brune 45744f7e39eSPeter Brune Notes: This implements the L-BFGS algorithm for the solution of F(x) = b using previous change in F(x) and x to 4586cc8130cSPeter Brune form the approximate inverse Jacobian using a series of multiplicative rank-one updates. This will eventually be 4596cc8130cSPeter Brune generalized to implement several limited-memory Broyden methods. 4606cc8130cSPeter Brune 4611867fe5bSPeter Brune When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied. The first of 4621867fe5bSPeter Brune these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this 4631867fe5bSPeter Brune iteration as the current iteration's values when constructing the approximate jacobian. The second, composed, 4641867fe5bSPeter Brune perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner. 4651867fe5bSPeter Brune 4666cc8130cSPeter Brune References: 4676cc8130cSPeter Brune 4686cc8130cSPeter Brune L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed, 4696cc8130cSPeter Brune International Journal of Computer Mathematics, vol. 86, 2009. 4706cc8130cSPeter Brune 4714b11644fSPeter Brune 4724b11644fSPeter Brune Level: beginner 4734b11644fSPeter Brune 4744b11644fSPeter Brune .seealso: SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR 4756cc8130cSPeter Brune 4764b11644fSPeter Brune M*/ 4774b11644fSPeter Brune EXTERN_C_BEGIN 4784b11644fSPeter Brune #undef __FUNCT__ 4794b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN" 4804b11644fSPeter Brune PetscErrorCode SNESCreate_QN(SNES snes) 4814b11644fSPeter Brune { 4824b11644fSPeter Brune 4834b11644fSPeter Brune PetscErrorCode ierr; 4849f83bee8SJed Brown SNES_QN *qn; 4854b11644fSPeter Brune 4864b11644fSPeter Brune PetscFunctionBegin; 4874b11644fSPeter Brune snes->ops->setup = SNESSetUp_QN; 4884b11644fSPeter Brune snes->ops->solve = SNESSolve_QN; 4894b11644fSPeter Brune snes->ops->destroy = SNESDestroy_QN; 4904b11644fSPeter Brune snes->ops->setfromoptions = SNESSetFromOptions_QN; 4914b11644fSPeter Brune snes->ops->view = 0; 4924b11644fSPeter Brune snes->ops->reset = SNESReset_QN; 4934b11644fSPeter Brune 49442f4f86dSBarry Smith snes->usespc = PETSC_TRUE; 49542f4f86dSBarry Smith snes->usesksp = PETSC_FALSE; 49642f4f86dSBarry Smith 4970e444f03SPeter Brune snes->max_funcs = 30000; 4980e444f03SPeter Brune snes->max_its = 10000; 4990e444f03SPeter Brune 5009f83bee8SJed Brown ierr = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr); 5014b11644fSPeter Brune snes->data = (void *) qn; 5020ecc9e1dSPeter Brune qn->m = 10; 503b21d5a53SPeter Brune qn->scaling = 1.0; 5044b11644fSPeter Brune qn->dX = PETSC_NULL; 5056bf1b2e5SPeter Brune qn->dF = PETSC_NULL; 50644f7e39eSPeter Brune qn->monitor = PETSC_NULL; 50788d374b2SPeter Brune qn->powell_gamma = 0.9; 50888d374b2SPeter Brune qn->powell_downhill = 0.2; 50988d374b2SPeter Brune qn->compositiontype = SNES_QN_SEQUENTIAL; 5100ecc9e1dSPeter Brune qn->scalingtype = SNES_QN_SHANNOSCALE; 5110ecc9e1dSPeter Brune qn->n_restart = -1; 512ea630c6eSPeter Brune 51392c02d66SPeter Brune ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_QN",SNESLineSearchSetType_QN);CHKERRQ(ierr); 514f3aaf736SPeter Brune ierr = SNESLineSearchSetType(snes, SNES_LS_CRITICAL);CHKERRQ(ierr); 5159f3a0142SPeter Brune 5164b11644fSPeter Brune PetscFunctionReturn(0); 5174b11644fSPeter Brune } 5184b11644fSPeter Brune EXTERN_C_END 519