1b45d2f2cSJed Brown #include <petsc-private/snesimpl.h> 24b11644fSPeter Brune 38e231d97SPeter Brune #define H(i,j) qn->dXdFmat[i*qn->m + j] 48e231d97SPeter Brune 588d374b2SPeter Brune typedef enum {SNES_QN_SEQUENTIAL, SNES_QN_COMPOSED} SNESQNCompositionType; 60ecc9e1dSPeter Brune typedef enum {SNES_QN_SHANNOSCALE, SNES_QN_LSSCALE, SNES_QN_JACOBIANSCALE} SNESQNScalingType; 76bf1b2e5SPeter Brune 84b11644fSPeter Brune typedef struct { 94b11644fSPeter Brune Vec *dX; /* The change in X */ 106bf1b2e5SPeter Brune Vec *dF; /* The change in F */ 118e231d97SPeter Brune PetscInt m; /* The number of kept previous steps */ 128e231d97SPeter Brune PetscScalar *alpha, *beta; 138e231d97SPeter Brune PetscScalar *dXtdF, *dFtdX, *YtdX; 148e231d97SPeter Brune PetscBool aggreduct; /* Aggregated reduction implementation */ 158e231d97SPeter Brune PetscScalar *dXdFmat; /* A matrix of values for dX_i dot dF_j */ 1644f7e39eSPeter Brune PetscViewer monitor; 176bf1b2e5SPeter Brune PetscReal powell_gamma; /* Powell angle restart condition */ 186bf1b2e5SPeter Brune PetscReal powell_downhill; /* Powell descent restart condition */ 19b21d5a53SPeter Brune PetscReal scaling; /* scaling of H0 */ 200ecc9e1dSPeter Brune PetscInt n_restart; /* the maximum iterations between restart */ 2188d374b2SPeter Brune 2288d374b2SPeter Brune SNESQNCompositionType compositiontype; /* determine if the composition is done sequentially or as a composition */ 230ecc9e1dSPeter Brune SNESQNScalingType scalingtype; /* determine if the composition is done sequentially or as a composition */ 2488d374b2SPeter Brune 259f83bee8SJed Brown } SNES_QN; 264b11644fSPeter Brune 274b11644fSPeter Brune #undef __FUNCT__ 288c40d5fbSBarry Smith #define __FUNCT__ "SNESQNApplyJinv_Private" 298c40d5fbSBarry Smith PetscErrorCode SNESQNApplyJinv_Private(SNES snes, PetscInt it, Vec D, Vec Y) { 304b11644fSPeter Brune 314b11644fSPeter Brune PetscErrorCode ierr; 324b11644fSPeter Brune 339f83bee8SJed Brown SNES_QN *qn = (SNES_QN*)snes->data; 344b11644fSPeter Brune 35335fb975SPeter Brune Vec Yin = snes->work[3]; 360ecc9e1dSPeter Brune 374b11644fSPeter Brune Vec *dX = qn->dX; 386bf1b2e5SPeter Brune Vec *dF = qn->dF; 394b11644fSPeter Brune 40bd052dfeSPeter Brune PetscScalar *alpha = qn->alpha; 41bd052dfeSPeter Brune PetscScalar *beta = qn->beta; 428e231d97SPeter Brune PetscScalar *dXtdF = qn->dXtdF; 438e231d97SPeter Brune PetscScalar *YtdX = qn->YtdX; 44bd052dfeSPeter Brune 450ecc9e1dSPeter Brune /* ksp thing for jacobian scaling */ 460ecc9e1dSPeter Brune KSPConvergedReason kspreason; 470ecc9e1dSPeter Brune MatStructure flg = DIFFERENT_NONZERO_PATTERN; 480ecc9e1dSPeter Brune 498e231d97SPeter Brune PetscInt k, i, j, g, lits; 504b11644fSPeter Brune PetscInt m = qn->m; 514b11644fSPeter Brune PetscScalar t; 524b11644fSPeter Brune PetscInt l = m; 534b11644fSPeter Brune 548e231d97SPeter Brune Mat jac, jac_pre; 558e231d97SPeter Brune 564b11644fSPeter Brune PetscFunctionBegin; 574b11644fSPeter Brune 583af51624SPeter Brune ierr = VecCopy(D, Y);CHKERRQ(ierr); 594b11644fSPeter Brune 605ba6227bSPeter Brune if (it < m) l = it; 614b11644fSPeter Brune 628e231d97SPeter Brune if (qn->aggreduct) { 638e231d97SPeter Brune ierr = VecMDot(Y, l, qn->dX, YtdX);CHKERRQ(ierr); 648e231d97SPeter Brune } 654b11644fSPeter Brune /* outward recursion starting at iteration k's update and working back */ 664b11644fSPeter Brune for (i = 0; i < l; i++) { 67b21d5a53SPeter Brune k = (it - i - 1) % l; 688e231d97SPeter Brune if (qn->aggreduct) { 698e231d97SPeter Brune /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */ 708e231d97SPeter Brune t = YtdX[k]; 718e231d97SPeter Brune for (j = 0; j < i; j++) { 728e231d97SPeter Brune g = (it - j - 1) % l; 738e231d97SPeter Brune t += -alpha[g]*H(g, k); 748e231d97SPeter Brune } 758e231d97SPeter Brune alpha[k] = t / H(k, k); 768e231d97SPeter Brune } else { 773af51624SPeter Brune ierr = VecDot(dX[k], Y, &t);CHKERRQ(ierr); 788e231d97SPeter Brune alpha[k] = t / dXtdF[k]; 798e231d97SPeter Brune } 8044f7e39eSPeter Brune if (qn->monitor) { 813af51624SPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 825ba6227bSPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); 833af51624SPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 8444f7e39eSPeter Brune } 856bf1b2e5SPeter Brune ierr = VecAXPY(Y, -alpha[k], dF[k]);CHKERRQ(ierr); 864b11644fSPeter Brune } 874b11644fSPeter Brune 880ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 898e231d97SPeter Brune ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 908e231d97SPeter Brune ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr); 910ecc9e1dSPeter Brune ierr = SNES_KSPSolve(snes,snes->ksp,Y,Yin);CHKERRQ(ierr); 920ecc9e1dSPeter Brune ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 930ecc9e1dSPeter Brune if (kspreason < 0) { 940ecc9e1dSPeter Brune if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 950ecc9e1dSPeter 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); 960ecc9e1dSPeter Brune snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 970ecc9e1dSPeter Brune PetscFunctionReturn(0); 980ecc9e1dSPeter Brune } 990ecc9e1dSPeter Brune } 1000ecc9e1dSPeter Brune ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 1010ecc9e1dSPeter Brune snes->linear_its += lits; 1020ecc9e1dSPeter Brune ierr = VecCopy(Yin, Y);CHKERRQ(ierr); 1030ecc9e1dSPeter Brune } else { 104b21d5a53SPeter Brune ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); 1050ecc9e1dSPeter Brune } 1068e231d97SPeter Brune if (qn->aggreduct) { 1078e231d97SPeter Brune ierr = VecMDot(Y, l, qn->dF, YtdX);CHKERRQ(ierr); 1088e231d97SPeter Brune } 1094b11644fSPeter Brune /* inward recursion starting at the first update and working forward */ 110bd052dfeSPeter Brune for (i = 0; i < l; i++) { 111b21d5a53SPeter Brune k = (it + i - l) % l; 1128e231d97SPeter Brune if (qn->aggreduct) { 1138e231d97SPeter Brune t = YtdX[k]; 1148e231d97SPeter Brune for (j = 0; j < i; j++) { 1158e231d97SPeter Brune g = (it + j - l) % l; 1168e231d97SPeter Brune t += (alpha[g] - beta[g])*H(k, g); 1178e231d97SPeter Brune } 1188e231d97SPeter Brune beta[k] = t / H(k, k); 1198e231d97SPeter Brune } else { 1206bf1b2e5SPeter Brune ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); 1218e231d97SPeter Brune beta[k] = t / dXtdF[k]; 1228e231d97SPeter Brune } 1233af51624SPeter Brune ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]); 12444f7e39eSPeter Brune if (qn->monitor) { 1253af51624SPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 1265ba6227bSPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); 1273af51624SPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 12844f7e39eSPeter Brune } 1294b11644fSPeter Brune } 1304b11644fSPeter Brune PetscFunctionReturn(0); 1314b11644fSPeter Brune } 1324b11644fSPeter Brune 1334b11644fSPeter Brune #undef __FUNCT__ 1344b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN" 1354b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes) 1364b11644fSPeter Brune { 1374b11644fSPeter Brune 1384b11644fSPeter Brune PetscErrorCode ierr; 1399f83bee8SJed Brown SNES_QN *qn = (SNES_QN*) snes->data; 1404b11644fSPeter Brune 14115f5eeeaSPeter Brune Vec X, Xold; 142335fb975SPeter Brune Vec F, B; 143335fb975SPeter Brune Vec Y, FPC, D, Dold; 1443af51624SPeter Brune SNESConvergedReason reason; 1458e231d97SPeter Brune PetscInt i, i_r, k, l, j; 1464b11644fSPeter Brune 147335fb975SPeter Brune PetscReal fnorm, xnorm, ynorm, gnorm; 1484b11644fSPeter Brune PetscInt m = qn->m; 149335fb975SPeter Brune PetscBool lssucceed; 1504b11644fSPeter Brune 151bd052dfeSPeter Brune Vec *dX = qn->dX; 1526bf1b2e5SPeter Brune Vec *dF = qn->dF; 1538e231d97SPeter Brune PetscScalar *dXtdF = qn->dXtdF; 1548e231d97SPeter Brune PetscScalar *dFtdX = qn->dFtdX; 15588d374b2SPeter Brune PetscScalar DolddotD, DolddotDold, DdotD, YdotD, a; 1564b11644fSPeter Brune 1570ecc9e1dSPeter Brune MatStructure flg = DIFFERENT_NONZERO_PATTERN; 1580ecc9e1dSPeter Brune 1594b11644fSPeter Brune /* basically just a regular newton's method except for the application of the jacobian */ 1604b11644fSPeter Brune PetscFunctionBegin; 1614b11644fSPeter Brune 1629f3a0142SPeter Brune X = snes->vec_sol; /* solution vector */ 1639f3a0142SPeter Brune F = snes->vec_func; /* residual vector */ 1643af51624SPeter Brune Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 1653af51624SPeter Brune B = snes->vec_rhs; 166335fb975SPeter Brune Xold = snes->work[0]; 1673af51624SPeter Brune 1683af51624SPeter Brune /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ 169335fb975SPeter Brune D = snes->work[1]; 170335fb975SPeter Brune Dold = snes->work[2]; 1714b11644fSPeter Brune 1724b11644fSPeter Brune snes->reason = SNES_CONVERGED_ITERATING; 1734b11644fSPeter Brune 1744b11644fSPeter Brune ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1754b11644fSPeter Brune snes->iter = 0; 1764b11644fSPeter Brune snes->norm = 0.; 1774b11644fSPeter Brune ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 178*e4ed7901SPeter Brune if (!snes->vec_func_init_set){ 17915f5eeeaSPeter Brune ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 1804b11644fSPeter Brune if (snes->domainerror) { 1814b11644fSPeter Brune snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 1824b11644fSPeter Brune PetscFunctionReturn(0); 1834b11644fSPeter Brune } 184*e4ed7901SPeter Brune } else { 185*e4ed7901SPeter Brune snes->vec_func_init_set = PETSC_FALSE; 186*e4ed7901SPeter Brune } 187*e4ed7901SPeter Brune 188*e4ed7901SPeter Brune if (!snes->norm_init_set) { 18915f5eeeaSPeter Brune ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1904b11644fSPeter Brune if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 191*e4ed7901SPeter Brune } else { 192*e4ed7901SPeter Brune fnorm = snes->norm_init; 193*e4ed7901SPeter Brune snes->norm_init_set = PETSC_FALSE; 194*e4ed7901SPeter Brune } 195*e4ed7901SPeter Brune 1964b11644fSPeter Brune ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1974b11644fSPeter Brune snes->norm = fnorm; 1984b11644fSPeter Brune ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1994b11644fSPeter Brune SNESLogConvHistory(snes,fnorm,0); 2004b11644fSPeter Brune ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 2014b11644fSPeter Brune 2024b11644fSPeter Brune /* set parameter for default relative tolerance convergence test */ 2034b11644fSPeter Brune snes->ttol = fnorm*snes->rtol; 2044b11644fSPeter Brune /* test convergence */ 2054b11644fSPeter Brune ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 2064b11644fSPeter Brune if (snes->reason) PetscFunctionReturn(0); 20770d3b23bSPeter Brune 20888d374b2SPeter Brune /* composed solve -- either sequential or composed */ 20988d374b2SPeter Brune if (snes->pc) { 21088d374b2SPeter Brune if (qn->compositiontype == SNES_QN_SEQUENTIAL) { 21188d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 21288d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 21388d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 21488d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 21588d374b2SPeter Brune PetscFunctionReturn(0); 21688d374b2SPeter Brune } 21788d374b2SPeter Brune ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 21888d374b2SPeter Brune ierr = VecCopy(FPC, F);CHKERRQ(ierr); 21988d374b2SPeter Brune ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); 2206bf1b2e5SPeter Brune ierr = VecCopy(F, Y);CHKERRQ(ierr); 22188d374b2SPeter Brune } else { 22288d374b2SPeter Brune ierr = VecCopy(X, Y);CHKERRQ(ierr); 22388d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, Y);CHKERRQ(ierr); 22488d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 22588d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 22688d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 22788d374b2SPeter Brune PetscFunctionReturn(0); 22888d374b2SPeter Brune } 22988d374b2SPeter Brune ierr = VecAYPX(Y,-1.0,X);CHKERRQ(ierr); 23088d374b2SPeter Brune } 23188d374b2SPeter Brune } else { 23288d374b2SPeter Brune ierr = VecCopy(F, Y);CHKERRQ(ierr); 23388d374b2SPeter Brune } 23488d374b2SPeter Brune ierr = VecCopy(Y, D);CHKERRQ(ierr); 2353af51624SPeter Brune 236f8e15203SPeter Brune /* scale the initial update */ 2370ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 2380ecc9e1dSPeter Brune ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 2390ecc9e1dSPeter Brune } 2400ecc9e1dSPeter Brune 2415ba6227bSPeter Brune for(i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 2428c40d5fbSBarry Smith ierr = SNESQNApplyJinv_Private(snes, i_r, D, Y);CHKERRQ(ierr); 24370d3b23bSPeter Brune /* line search for lambda */ 24470d3b23bSPeter Brune ynorm = 1; gnorm = fnorm; 24588d374b2SPeter Brune ierr = VecCopy(D, Dold);CHKERRQ(ierr); 24615f5eeeaSPeter Brune ierr = VecCopy(X, Xold);CHKERRQ(ierr); 247f1c6b773SPeter Brune ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); 2489f3a0142SPeter Brune if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 2499f3a0142SPeter Brune if (snes->domainerror) { 2509f3a0142SPeter Brune snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 2519f3a0142SPeter Brune PetscFunctionReturn(0); 2529f3a0142SPeter Brune } 253f1c6b773SPeter Brune ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 2549f3a0142SPeter Brune if (!lssucceed) { 2559f3a0142SPeter Brune if (++snes->numFailures >= snes->maxFailures) { 2569f3a0142SPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 2579f3a0142SPeter Brune break; 2589f3a0142SPeter Brune } 2599f3a0142SPeter Brune } 260f1c6b773SPeter Brune ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); 2610ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_LSSCALE) { 262f1c6b773SPeter Brune ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); 2630ecc9e1dSPeter Brune } 2643af51624SPeter Brune 26588d374b2SPeter Brune /* convergence monitoring */ 266b21d5a53SPeter 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); 267b21d5a53SPeter Brune 268360c497dSPeter Brune ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 269360c497dSPeter Brune ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); 270360c497dSPeter Brune 2718409ca45SMatthew G Knepley SNESLogConvHistory(snes,snes->norm,snes->iter); 2728409ca45SMatthew G Knepley ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 2734b11644fSPeter Brune /* set parameter for default relative tolerance convergence test */ 2745ba6227bSPeter Brune ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 2754b11644fSPeter Brune if (snes->reason) PetscFunctionReturn(0); 2764b11644fSPeter Brune 27788d374b2SPeter Brune 27888d374b2SPeter Brune if (snes->pc) { 27988d374b2SPeter Brune if (qn->compositiontype == SNES_QN_SEQUENTIAL) { 28088d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 28188d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 28288d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 28388d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 28488d374b2SPeter Brune PetscFunctionReturn(0); 28588d374b2SPeter Brune } 28688d374b2SPeter Brune ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 28788d374b2SPeter Brune ierr = VecCopy(FPC, F);CHKERRQ(ierr); 28888d374b2SPeter Brune ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); 28988d374b2SPeter Brune ierr = VecCopy(F, D);CHKERRQ(ierr); 29088d374b2SPeter Brune } else { 29188d374b2SPeter Brune ierr = VecCopy(X, D);CHKERRQ(ierr); 29288d374b2SPeter Brune ierr = SNESSolve(snes->pc, B, D);CHKERRQ(ierr); 29388d374b2SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 29488d374b2SPeter Brune if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { 29588d374b2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 29688d374b2SPeter Brune PetscFunctionReturn(0); 29788d374b2SPeter Brune } 29888d374b2SPeter Brune ierr = VecAYPX(D,-1.0,X);CHKERRQ(ierr); 29988d374b2SPeter Brune } 30088d374b2SPeter Brune } else { 30188d374b2SPeter Brune ierr = VecCopy(F, D);CHKERRQ(ierr); 30288d374b2SPeter Brune } 30388d374b2SPeter Brune 3046bf1b2e5SPeter Brune /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 3058e231d97SPeter Brune ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr); 3068e231d97SPeter Brune ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr); 3078e231d97SPeter Brune ierr = VecDotBegin(D, D, &DdotD);CHKERRQ(ierr); 3088e231d97SPeter Brune ierr = VecDotBegin(Y, D, &YdotD);CHKERRQ(ierr); 3098e231d97SPeter Brune ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr); 3108e231d97SPeter Brune ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr); 3118e231d97SPeter Brune ierr = VecDotEnd(D, D, &DdotD);CHKERRQ(ierr); 3128e231d97SPeter Brune ierr = VecDotEnd(Y, D, &YdotD);CHKERRQ(ierr); 3130ecc9e1dSPeter Brune if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold)) || (i_r > qn->n_restart - 1 && qn->n_restart > 0)) { 3145ba6227bSPeter Brune if (qn->monitor) { 3155ba6227bSPeter Brune ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 316516fe3c3SPeter Brune ierr = PetscViewerASCIIPrintf(qn->monitor, "restart! |%14.12e| > %4.2f*|%14.12e| or i_r = %d\n", PetscRealPart(DolddotD), qn->powell_gamma, PetscRealPart(DolddotDold), i_r);CHKERRQ(ierr); 3175ba6227bSPeter Brune ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 3185ba6227bSPeter Brune } 3195ba6227bSPeter Brune i_r = -1; 3205ba6227bSPeter Brune /* general purpose update */ 3215ba6227bSPeter Brune if (snes->ops->update) { 3225ba6227bSPeter Brune ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 3235ba6227bSPeter Brune } 3240ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 3250ecc9e1dSPeter Brune ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 3260ecc9e1dSPeter Brune } 3275ba6227bSPeter Brune } else { 328bd052dfeSPeter Brune /* set the differences */ 3295ba6227bSPeter Brune k = i_r % m; 3308e231d97SPeter Brune l = m; 3318e231d97SPeter Brune if (i_r + 1 < m) l = i_r + 1; 33288d374b2SPeter Brune ierr = VecCopy(D, dF[k]);CHKERRQ(ierr); 33388d374b2SPeter Brune ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr); 33415f5eeeaSPeter Brune ierr = VecCopy(X, dX[k]);CHKERRQ(ierr); 33515f5eeeaSPeter Brune ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr); 3368e231d97SPeter Brune if (qn->aggreduct) { 3378e231d97SPeter Brune ierr = VecMDot(dF[k], l, dX, dXtdF);CHKERRQ(ierr); 3388e231d97SPeter Brune ierr = VecMDot(dX[k], l, dF, dFtdX);CHKERRQ(ierr); 3398e231d97SPeter Brune for (j = 0; j < l; j++) { 3408e231d97SPeter Brune H(k, j) = dFtdX[j]; 3418e231d97SPeter Brune H(j, k) = dXtdF[j]; 3428e231d97SPeter Brune } 3438e231d97SPeter Brune /* copy back over to make the computation of alpha and beta easier */ 3448e231d97SPeter Brune for (j = 0; j < l; j++) { 3458e231d97SPeter Brune dXtdF[j] = H(j, j); 3468e231d97SPeter Brune } 3478e231d97SPeter Brune } else { 3488e231d97SPeter Brune ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr); 3498e231d97SPeter Brune } 3506bf1b2e5SPeter Brune /* set scaling to be shanno scaling */ 3510ecc9e1dSPeter Brune if (qn->scalingtype == SNES_QN_SHANNOSCALE) { 3526bf1b2e5SPeter Brune ierr = VecDot(dF[k], dF[k], &a);CHKERRQ(ierr); 3538e231d97SPeter Brune qn->scaling = PetscRealPart(dXtdF[k]) / PetscRealPart(a); 3540ecc9e1dSPeter Brune } 35570d3b23bSPeter Brune /* general purpose update */ 35670d3b23bSPeter Brune if (snes->ops->update) { 35770d3b23bSPeter Brune ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 35870d3b23bSPeter Brune } 3595ba6227bSPeter Brune } 3604b11644fSPeter Brune } 3614b11644fSPeter Brune if (i == snes->max_its) { 3624b11644fSPeter Brune ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 3634b11644fSPeter Brune if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 3644b11644fSPeter Brune } 3654b11644fSPeter Brune PetscFunctionReturn(0); 3664b11644fSPeter Brune } 3674b11644fSPeter Brune 3684b11644fSPeter Brune 3694b11644fSPeter Brune #undef __FUNCT__ 3704b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN" 3714b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes) 3724b11644fSPeter Brune { 3739f83bee8SJed Brown SNES_QN *qn = (SNES_QN*)snes->data; 3744b11644fSPeter Brune PetscErrorCode ierr; 375335fb975SPeter Brune 3764b11644fSPeter Brune PetscFunctionBegin; 3774b11644fSPeter Brune ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->dX);CHKERRQ(ierr); 3786bf1b2e5SPeter Brune ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->dF);CHKERRQ(ierr); 3798e231d97SPeter Brune ierr = PetscMalloc3(qn->m, PetscScalar, &qn->alpha, 3808e231d97SPeter Brune qn->m, PetscScalar, &qn->beta, 3818e231d97SPeter Brune qn->m, PetscScalar, &qn->dXtdF);CHKERRQ(ierr); 3828e231d97SPeter Brune 3838e231d97SPeter Brune if (qn->aggreduct) { 3848e231d97SPeter Brune ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat, 3858e231d97SPeter Brune qn->m, PetscScalar, &qn->dFtdX, 3868e231d97SPeter Brune qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr); 3878e231d97SPeter Brune } 388335fb975SPeter Brune ierr = SNESDefaultGetWork(snes,4);CHKERRQ(ierr); 389335fb975SPeter Brune 390335fb975SPeter Brune /* set up the line search */ 3918e231d97SPeter Brune if (qn->scalingtype == SNES_QN_JACOBIANSCALE) { 3928e231d97SPeter Brune ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); 3938e231d97SPeter Brune } 3944b11644fSPeter Brune PetscFunctionReturn(0); 3954b11644fSPeter Brune } 3964b11644fSPeter Brune 3974b11644fSPeter Brune #undef __FUNCT__ 3984b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN" 3994b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes) 4004b11644fSPeter Brune { 4014b11644fSPeter Brune PetscErrorCode ierr; 4029f83bee8SJed Brown SNES_QN *qn; 4034b11644fSPeter Brune PetscFunctionBegin; 4044b11644fSPeter Brune if (snes->data) { 4059f83bee8SJed Brown qn = (SNES_QN*)snes->data; 4064b11644fSPeter Brune if (qn->dX) { 4074b11644fSPeter Brune ierr = VecDestroyVecs(qn->m, &qn->dX);CHKERRQ(ierr); 4084b11644fSPeter Brune } 4096bf1b2e5SPeter Brune if (qn->dF) { 4106bf1b2e5SPeter Brune ierr = VecDestroyVecs(qn->m, &qn->dF);CHKERRQ(ierr); 4114b11644fSPeter Brune } 4128e231d97SPeter Brune if (qn->aggreduct) { 4138e231d97SPeter Brune ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr); 4148e231d97SPeter Brune } 4158e231d97SPeter Brune ierr = PetscFree3(qn->alpha, qn->beta, qn->dXtdF);CHKERRQ(ierr); 4164b11644fSPeter Brune } 4174b11644fSPeter Brune PetscFunctionReturn(0); 4184b11644fSPeter Brune } 4194b11644fSPeter Brune 4204b11644fSPeter Brune #undef __FUNCT__ 4214b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN" 4224b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes) 4234b11644fSPeter Brune { 4244b11644fSPeter Brune PetscErrorCode ierr; 4254b11644fSPeter Brune PetscFunctionBegin; 4264b11644fSPeter Brune ierr = SNESReset_QN(snes);CHKERRQ(ierr); 4274b11644fSPeter Brune ierr = PetscFree(snes->data);CHKERRQ(ierr); 4289c05af5eSJed Brown ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"","",PETSC_NULL);CHKERRQ(ierr); 4294b11644fSPeter Brune PetscFunctionReturn(0); 4304b11644fSPeter Brune } 4314b11644fSPeter Brune 4324b11644fSPeter Brune #undef __FUNCT__ 4334b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN" 4344b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes) 4354b11644fSPeter Brune { 4364b11644fSPeter Brune 4374b11644fSPeter Brune PetscErrorCode ierr; 4389f83bee8SJed Brown SNES_QN *qn; 4395b4627e8SPeter Brune const char *compositions[] = {"sequential", "composed"}; 4400ecc9e1dSPeter Brune const char *scalings[] = {"shanno", "ls", "jacobian"}; 44188d374b2SPeter Brune PetscInt indx = 0; 44288d374b2SPeter Brune PetscBool flg; 44344f7e39eSPeter Brune PetscBool monflg = PETSC_FALSE; 444f1c6b773SPeter Brune SNESLineSearch linesearch; 4454b11644fSPeter Brune PetscFunctionBegin; 4464b11644fSPeter Brune 4479f83bee8SJed Brown qn = (SNES_QN*)snes->data; 4484b11644fSPeter Brune 4494b11644fSPeter Brune ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr); 4505b4627e8SPeter Brune ierr = PetscOptionsInt("-snes_qn_m", "Number of past states saved for L-BFGS methods", "SNESQN", qn->m, &qn->m, PETSC_NULL);CHKERRQ(ierr); 4510ecc9e1dSPeter Brune ierr = PetscOptionsInt("-snes_qn_restart", "Maximum number of iterations between restarts", "SNESQN", qn->n_restart, &qn->n_restart, PETSC_NULL);CHKERRQ(ierr); 4525b4627e8SPeter Brune ierr = PetscOptionsReal("-snes_qn_powell_gamma", "Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, PETSC_NULL);CHKERRQ(ierr); 4535b4627e8SPeter Brune ierr = PetscOptionsReal("-snes_qn_powell_downhill", "Powell descent tolerance", "SNESQN", qn->powell_downhill, &qn->powell_downhill, PETSC_NULL);CHKERRQ(ierr); 4545b4627e8SPeter Brune ierr = PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", monflg, &monflg, PETSC_NULL);CHKERRQ(ierr); 4558e231d97SPeter Brune ierr = PetscOptionsBool("-snes_qn_aggreduct", "Aggregate reductions", "SNESQN", qn->aggreduct, &qn->aggreduct, PETSC_NULL);CHKERRQ(ierr); 4565b4627e8SPeter Brune ierr = PetscOptionsEList("-snes_qn_composition", "Composition type", "SNESQN",compositions,2,"sequential",&indx,&flg);CHKERRQ(ierr); 45788d374b2SPeter Brune if (flg) { 45888d374b2SPeter Brune switch (indx) { 4595b4627e8SPeter Brune case 0: qn->compositiontype = SNES_QN_SEQUENTIAL; 4605b4627e8SPeter Brune break; 4615b4627e8SPeter Brune case 1: qn->compositiontype = SNES_QN_COMPOSED; 4625b4627e8SPeter Brune break; 46388d374b2SPeter Brune } 46488d374b2SPeter Brune } 4650ecc9e1dSPeter Brune ierr = PetscOptionsEList("-snes_qn_scaling", "Scaling type", "SNESQN",scalings,3,"shanno",&indx,&flg);CHKERRQ(ierr); 4660ecc9e1dSPeter Brune if (flg) { 4670ecc9e1dSPeter Brune switch (indx) { 4680ecc9e1dSPeter Brune case 0: qn->scalingtype = SNES_QN_SHANNOSCALE; 4690ecc9e1dSPeter Brune break; 4700ecc9e1dSPeter Brune case 1: qn->scalingtype = SNES_QN_LSSCALE; 4710ecc9e1dSPeter Brune break; 4720ecc9e1dSPeter Brune case 2: qn->scalingtype = SNES_QN_JACOBIANSCALE; 4730ecc9e1dSPeter Brune snes->usesksp = PETSC_TRUE; 4740ecc9e1dSPeter Brune break; 4750ecc9e1dSPeter Brune } 4760ecc9e1dSPeter Brune } 4770ecc9e1dSPeter Brune 4784b11644fSPeter Brune ierr = PetscOptionsTail();CHKERRQ(ierr); 4799e764e56SPeter Brune if (!snes->linesearch) { 480f1c6b773SPeter Brune ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr); 4819e764e56SPeter Brune if (!snes->pc || qn->compositiontype == SNES_QN_SEQUENTIAL) { 482f1c6b773SPeter Brune ierr = SNESLineSearchSetType(linesearch, SNES_LINESEARCH_CP);CHKERRQ(ierr); 4839e764e56SPeter Brune } else { 484f1c6b773SPeter Brune ierr = SNESLineSearchSetType(linesearch, SNES_LINESEARCH_L2);CHKERRQ(ierr); 4859e764e56SPeter Brune } 4869e764e56SPeter Brune } 48744f7e39eSPeter Brune if (monflg) { 48844f7e39eSPeter Brune qn->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 48944f7e39eSPeter Brune } 4904b11644fSPeter Brune PetscFunctionReturn(0); 4914b11644fSPeter Brune } 4924b11644fSPeter Brune 49392c02d66SPeter Brune 4944b11644fSPeter Brune /* -------------------------------------------------------------------------- */ 4954b11644fSPeter Brune /*MC 4964b11644fSPeter Brune SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems. 4974b11644fSPeter Brune 4986cc8130cSPeter Brune Options Database: 4996cc8130cSPeter Brune 5006cc8130cSPeter Brune + -snes_qn_m - Number of past states saved for the L-Broyden methods. 5011867fe5bSPeter Brune . -snes_qn_powell_angle - Angle condition for restart. 5021867fe5bSPeter Brune . -snes_qn_powell_descent - Descent condition for restart. 5031867fe5bSPeter Brune . -snes_qn_composition <sequential, composed>- Type of composition. 504f3aaf736SPeter Brune . -snes_ls <basic, basicnonorms, quadratic, critical> - Type of line search. 50544f7e39eSPeter Brune - -snes_qn_monitor - Monitors the quasi-newton jacobian. 5066cc8130cSPeter Brune 50744f7e39eSPeter Brune Notes: This implements the L-BFGS algorithm for the solution of F(x) = b using previous change in F(x) and x to 5086cc8130cSPeter Brune form the approximate inverse Jacobian using a series of multiplicative rank-one updates. This will eventually be 5096cc8130cSPeter Brune generalized to implement several limited-memory Broyden methods. 5106cc8130cSPeter Brune 5111867fe5bSPeter Brune When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied. The first of 5121867fe5bSPeter Brune these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this 5131867fe5bSPeter Brune iteration as the current iteration's values when constructing the approximate jacobian. The second, composed, 5141867fe5bSPeter Brune perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner. 5151867fe5bSPeter Brune 5166cc8130cSPeter Brune References: 5176cc8130cSPeter Brune 5186cc8130cSPeter Brune L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed, 5196cc8130cSPeter Brune International Journal of Computer Mathematics, vol. 86, 2009. 5206cc8130cSPeter Brune 5214b11644fSPeter Brune 5224b11644fSPeter Brune Level: beginner 5234b11644fSPeter Brune 5244b11644fSPeter Brune .seealso: SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR 5256cc8130cSPeter Brune 5264b11644fSPeter Brune M*/ 5274b11644fSPeter Brune EXTERN_C_BEGIN 5284b11644fSPeter Brune #undef __FUNCT__ 5294b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN" 5304b11644fSPeter Brune PetscErrorCode SNESCreate_QN(SNES snes) 5314b11644fSPeter Brune { 5324b11644fSPeter Brune 5334b11644fSPeter Brune PetscErrorCode ierr; 5349f83bee8SJed Brown SNES_QN *qn; 5354b11644fSPeter Brune 5364b11644fSPeter Brune PetscFunctionBegin; 5374b11644fSPeter Brune snes->ops->setup = SNESSetUp_QN; 5384b11644fSPeter Brune snes->ops->solve = SNESSolve_QN; 5394b11644fSPeter Brune snes->ops->destroy = SNESDestroy_QN; 5404b11644fSPeter Brune snes->ops->setfromoptions = SNESSetFromOptions_QN; 5414b11644fSPeter Brune snes->ops->view = 0; 5424b11644fSPeter Brune snes->ops->reset = SNESReset_QN; 5434b11644fSPeter Brune 54442f4f86dSBarry Smith snes->usespc = PETSC_TRUE; 54542f4f86dSBarry Smith snes->usesksp = PETSC_FALSE; 54642f4f86dSBarry Smith 54788976e71SPeter Brune if (!snes->tolerancesset) { 5480e444f03SPeter Brune snes->max_funcs = 30000; 5490e444f03SPeter Brune snes->max_its = 10000; 55088976e71SPeter Brune } 5510e444f03SPeter Brune 5529f83bee8SJed Brown ierr = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr); 5534b11644fSPeter Brune snes->data = (void *) qn; 5540ecc9e1dSPeter Brune qn->m = 10; 555b21d5a53SPeter Brune qn->scaling = 1.0; 5564b11644fSPeter Brune qn->dX = PETSC_NULL; 5576bf1b2e5SPeter Brune qn->dF = PETSC_NULL; 5588e231d97SPeter Brune qn->dXtdF = PETSC_NULL; 5598e231d97SPeter Brune qn->dFtdX = PETSC_NULL; 5608e231d97SPeter Brune qn->dXdFmat = PETSC_NULL; 56144f7e39eSPeter Brune qn->monitor = PETSC_NULL; 5628e231d97SPeter Brune qn->aggreduct = PETSC_FALSE; 56388d374b2SPeter Brune qn->powell_gamma = 0.9; 56488d374b2SPeter Brune qn->powell_downhill = 0.2; 56588d374b2SPeter Brune qn->compositiontype = SNES_QN_SEQUENTIAL; 5660ecc9e1dSPeter Brune qn->scalingtype = SNES_QN_SHANNOSCALE; 5670ecc9e1dSPeter Brune qn->n_restart = -1; 568ea630c6eSPeter Brune 5694b11644fSPeter Brune PetscFunctionReturn(0); 5704b11644fSPeter Brune } 5718e231d97SPeter Brune 5724b11644fSPeter Brune EXTERN_C_END 573