xref: /petsc/src/snes/impls/qn/qn.c (revision 4279555e62e618147958e52682840638ab8c8be0)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
2fced5a79SAsbjørn Nilsen Riseth #include <petscdm.h>
34b11644fSPeter Brune 
48e231d97SPeter Brune #define H(i, j) qn->dXdFmat[i * qn->m + j]
58e231d97SPeter Brune 
69e5d0892SLisandro Dalcin const char *const SNESQNScaleTypes[]   = {"DEFAULT", "NONE", "SCALAR", "DIAGONAL", "JACOBIAN", "SNESQNScaleType", "SNES_QN_SCALING_", NULL};
79e5d0892SLisandro Dalcin const char *const SNESQNRestartTypes[] = {"DEFAULT", "NONE", "POWELL", "PERIODIC", "SNESQNRestartType", "SNES_QN_RESTART_", NULL};
89e5d0892SLisandro Dalcin const char *const SNESQNTypes[]        = {"LBFGS", "BROYDEN", "BADBROYDEN", "SNESQNType", "SNES_QN_", NULL};
9b8840d6bSPeter Brune 
104b11644fSPeter Brune typedef struct {
1192f76d53SAlp Dener   Mat               B;      /* Quasi-Newton approximation Matrix (MATLMVM) */
128e231d97SPeter Brune   PetscInt          m;      /* The number of kept previous steps */
135c7a0a03SPeter Brune   PetscReal        *lambda; /* The line search history of the method */
1492f76d53SAlp Dener   PetscBool         monflg;
1544f7e39eSPeter Brune   PetscViewer       monitor;
166bf1b2e5SPeter Brune   PetscReal         powell_gamma; /* Powell angle restart condition */
17b21d5a53SPeter Brune   PetscReal         scaling;      /* scaling of H0 */
18b8840d6bSPeter Brune   SNESQNType        type;         /* the type of quasi-newton method used */
1988f769c5SPeter Brune   SNESQNScaleType   scale_type;   /* the type of scaling used */
200c777b0cSPeter Brune   SNESQNRestartType restart_type; /* determine the frequency and type of restart conditions */
219f83bee8SJed Brown } SNES_QN;
224b11644fSPeter Brune 
23d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSolve_QN(SNES snes)
24d71ae5a4SJacob Faibussowitsch {
259f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN *)snes->data;
2615f5eeeaSPeter Brune   Vec                  X, Xold;
270a3905e1SPeter Brune   Vec                  F, W;
2847f26062SPeter Brune   Vec                  Y, D, Dold;
29b8840d6bSPeter Brune   PetscInt             i, i_r;
30*4279555eSSatish Balay   PetscReal            fnorm, xnorm, ynorm;
31422a814eSBarry Smith   SNESLineSearchReason lssucceed;
3292f76d53SAlp Dener   PetscBool            badstep, powell, periodic;
331c6523dcSPeter Brune   PetscScalar          DolddotD, DolddotDold;
34b7281c8aSPeter Brune   SNESConvergedReason  reason;
35*4279555eSSatish Balay #if defined(PETSC_USE_INFO)
36*4279555eSSatish Balay   PetscReal gnorm;
37*4279555eSSatish Balay #endif
380ecc9e1dSPeter Brune 
3984c577daSBarry Smith   /* basically just a regular newton's method except for the application of the Jacobian */
404b11644fSPeter Brune 
416e111a19SKarl Rupp   PetscFunctionBegin;
420b121fc5SBarry Smith   PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
43c579b300SPatrick Farrell 
449566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
459f3a0142SPeter Brune   F    = snes->vec_func;       /* residual vector */
463af51624SPeter Brune   Y    = snes->vec_sol_update; /* search direction generated by J^-1D*/
470a3905e1SPeter Brune   W    = snes->work[3];
48b8840d6bSPeter Brune   X    = snes->vec_sol; /* solution vector */
49335fb975SPeter Brune   Xold = snes->work[0];
503af51624SPeter Brune 
513af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
52335fb975SPeter Brune   D    = snes->work[1];
53335fb975SPeter Brune   Dold = snes->work[2];
544b11644fSPeter Brune 
554b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
564b11644fSPeter Brune 
579566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
584b11644fSPeter Brune   snes->iter = 0;
594b11644fSPeter Brune   snes->norm = 0.;
609566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
6147f26062SPeter Brune 
62efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
639566063dSJacob Faibussowitsch     PetscCall(SNESApplyNPC(snes, X, NULL, F));
649566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes->npc, &reason));
65b7281c8aSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
66b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
673ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
68b7281c8aSPeter Brune     }
699566063dSJacob Faibussowitsch     PetscCall(VecNorm(F, NORM_2, &fnorm));
7047f26062SPeter Brune   } else {
71e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
729566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, X, F));
731aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
74c1c75074SPeter Brune 
759566063dSJacob Faibussowitsch     PetscCall(VecNorm(F, NORM_2, &fnorm));
76422a814eSBarry Smith     SNESCheckFunctionNorm(snes, fnorm);
7747f26062SPeter Brune   }
78efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
799566063dSJacob Faibussowitsch     PetscCall(SNESApplyNPC(snes, X, F, D));
809566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes->npc, &reason));
81b7281c8aSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
82b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
833ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
84b7281c8aSPeter Brune     }
8547f26062SPeter Brune   } else {
869566063dSJacob Faibussowitsch     PetscCall(VecCopy(F, D));
8747f26062SPeter Brune   }
88b28a06ddSPeter Brune 
899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
904b11644fSPeter Brune   snes->norm = fnorm;
919566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
929566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
939566063dSJacob Faibussowitsch   PetscCall(SNESMonitor(snes, 0, fnorm));
944b11644fSPeter Brune 
954b11644fSPeter Brune   /* test convergence */
96dbbe0bcdSBarry Smith   PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
973ba16761SJacob Faibussowitsch   if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
9870d3b23bSPeter Brune 
99efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_RIGHT) {
1009566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, X, 0, 0));
1019566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes->npc, snes->vec_rhs, X));
1029566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, X, 0, 0));
1039566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes->npc, &reason));
104ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
105ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
1063ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
107ddd40ce5SPeter Brune     }
1089566063dSJacob Faibussowitsch     PetscCall(SNESGetNPCFunction(snes, F, &fnorm));
1099566063dSJacob Faibussowitsch     PetscCall(VecCopy(F, D));
1103cf07b75SPeter Brune   }
1113cf07b75SPeter Brune 
11201fe78eaSStefano Zampini   /* general purpose update */
113dbbe0bcdSBarry Smith   PetscTryTypeMethod(snes, update, snes->iter);
11401fe78eaSStefano Zampini 
115f8e15203SPeter Brune   /* scale the initial update */
1160c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
1179566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
11807b62357SFande Kong     SNESCheckJacobianDomainerror(snes);
1199566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian_pre));
1209566063dSJacob Faibussowitsch     PetscCall(MatLMVMSetJ0KSP(qn->B, snes->ksp));
1210ecc9e1dSPeter Brune   }
1220ecc9e1dSPeter Brune 
1235ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
12492f76d53SAlp Dener     /* update QN approx and calculate step */
1259566063dSJacob Faibussowitsch     PetscCall(MatLMVMUpdate(qn->B, X, D));
1269566063dSJacob Faibussowitsch     PetscCall(MatSolve(qn->B, D, Y));
12792f76d53SAlp Dener 
12870d3b23bSPeter Brune     /* line search for lambda */
1299371c9d4SSatish Balay     ynorm = 1;
130*4279555eSSatish Balay #if defined(PETSC_USE_INFO)
1319371c9d4SSatish Balay     gnorm = fnorm;
132*4279555eSSatish Balay #endif
1339566063dSJacob Faibussowitsch     PetscCall(VecCopy(D, Dold));
1349566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Xold));
1359566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y));
1369f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
1379566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed));
1389566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm));
13992f76d53SAlp Dener     badstep = PETSC_FALSE;
140422a814eSBarry Smith     if (lssucceed) {
1419f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
1429f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
1439f3a0142SPeter Brune         break;
1449f3a0142SPeter Brune       }
14592f76d53SAlp Dener       badstep = PETSC_TRUE;
1460ecc9e1dSPeter Brune     }
1473af51624SPeter Brune 
14888d374b2SPeter Brune     /* convergence monitoring */
1499566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed));
150b21d5a53SPeter Brune 
151efd4aadfSBarry Smith     if (snes->npc && snes->npcside == PC_RIGHT) {
1529566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, X, 0, 0));
1539566063dSJacob Faibussowitsch       PetscCall(SNESSolve(snes->npc, snes->vec_rhs, X));
1549566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, X, 0, 0));
1559566063dSJacob Faibussowitsch       PetscCall(SNESGetConvergedReason(snes->npc, &reason));
156ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
157ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
1583ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
159ddd40ce5SPeter Brune       }
1609566063dSJacob Faibussowitsch       PetscCall(SNESGetNPCFunction(snes, F, &fnorm));
161b28a06ddSPeter Brune     }
162b28a06ddSPeter Brune 
1639566063dSJacob Faibussowitsch     PetscCall(SNESSetIterationNumber(snes, i + 1));
16471dbe336SPeter Brune     snes->norm  = fnorm;
165c1e67a49SFande Kong     snes->xnorm = xnorm;
166c1e67a49SFande Kong     snes->ynorm = ynorm;
167360c497dSPeter Brune 
1689566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, snes->iter));
1699566063dSJacob Faibussowitsch     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
17092f76d53SAlp Dener 
1714b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
172dbbe0bcdSBarry Smith     PetscUseTypeMethod(snes, converged, snes->iter, xnorm, ynorm, fnorm, &snes->reason, snes->cnvP);
1733ba16761SJacob Faibussowitsch     if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
174efd4aadfSBarry Smith     if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
1759566063dSJacob Faibussowitsch       PetscCall(SNESApplyNPC(snes, X, F, D));
1769566063dSJacob Faibussowitsch       PetscCall(SNESGetConvergedReason(snes->npc, &reason));
177b7281c8aSPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
178b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
1793ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
180b7281c8aSPeter Brune       }
18188d374b2SPeter Brune     } else {
1829566063dSJacob Faibussowitsch       PetscCall(VecCopy(F, D));
18388d374b2SPeter Brune     }
18401fe78eaSStefano Zampini 
18501fe78eaSStefano Zampini     /* general purpose update */
186dbbe0bcdSBarry Smith     PetscTryTypeMethod(snes, update, snes->iter);
18701fe78eaSStefano Zampini 
18892f76d53SAlp Dener     /* restart conditions */
1890c777b0cSPeter Brune     powell = PETSC_FALSE;
1906bdcc836SBarry Smith     if (qn->restart_type == SNES_QN_RESTART_POWELL && i_r > 1) {
1916bdcc836SBarry Smith       /* check restart by Powell's Criterion: |F^T H_0 Fold| > powell_gamma * |Fold^T H_0 Fold| */
19223c918e7SPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
193574a8f54SStefano Zampini         PetscCall(MatMult(snes->jacobian, Dold, W));
19423c918e7SPeter Brune       } else {
1959566063dSJacob Faibussowitsch         PetscCall(VecCopy(Dold, W));
19623c918e7SPeter Brune       }
1979566063dSJacob Faibussowitsch       PetscCall(VecDotBegin(W, Dold, &DolddotDold));
1989566063dSJacob Faibussowitsch       PetscCall(VecDotBegin(W, D, &DolddotD));
1999566063dSJacob Faibussowitsch       PetscCall(VecDotEnd(W, Dold, &DolddotDold));
2009566063dSJacob Faibussowitsch       PetscCall(VecDotEnd(W, D, &DolddotD));
2010c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma * PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
2020c777b0cSPeter Brune     }
2030c777b0cSPeter Brune     periodic = PETSC_FALSE;
204b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
205b8840d6bSPeter Brune       if (i_r > qn->m - 1) periodic = PETSC_TRUE;
2060c777b0cSPeter Brune     }
2070c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
20892f76d53SAlp Dener     if (badstep || powell || periodic) {
20992f76d53SAlp Dener       if (qn->monflg) {
2109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(qn->monitor, ((PetscObject)snes)->tablevel + 2));
2116bdcc836SBarry Smith         if (powell) {
21263a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(qn->monitor, "Powell restart! |%14.12e| > %6.4f*|%14.12e| i_r = %" PetscInt_FMT "\n", (double)PetscRealPart(DolddotD), (double)qn->powell_gamma, (double)PetscRealPart(DolddotDold), i_r));
2136bdcc836SBarry Smith         } else {
21463a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(qn->monitor, "Periodic restart! i_r = %" PetscInt_FMT "\n", i_r));
2156bdcc836SBarry Smith         }
2169566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(qn->monitor, ((PetscObject)snes)->tablevel + 2));
2175ba6227bSPeter Brune       }
2185ba6227bSPeter Brune       i_r = -1;
2190c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
2209566063dSJacob Faibussowitsch         PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
22107b62357SFande Kong         SNESCheckJacobianDomainerror(snes);
2220ecc9e1dSPeter Brune       }
2239566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(qn->B, PETSC_FALSE));
2240ecc9e1dSPeter Brune     }
2255ba6227bSPeter Brune   }
2264b11644fSPeter Brune   if (i == snes->max_its) {
22763a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", snes->max_its));
2284b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
2294b11644fSPeter Brune   }
2303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2314b11644fSPeter Brune }
2324b11644fSPeter Brune 
233d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetUp_QN(SNES snes)
234d71ae5a4SJacob Faibussowitsch {
2359f83bee8SJed Brown   SNES_QN *qn = (SNES_QN *)snes->data;
236fced5a79SAsbjørn Nilsen Riseth   DM       dm;
23792f76d53SAlp Dener   PetscInt n, N;
238335fb975SPeter Brune 
2394b11644fSPeter Brune   PetscFunctionBegin;
240fced5a79SAsbjørn Nilsen Riseth 
241fced5a79SAsbjørn Nilsen Riseth   if (!snes->vec_sol) {
2429566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
2439566063dSJacob Faibussowitsch     PetscCall(DMCreateGlobalVector(dm, &snes->vec_sol));
244fced5a79SAsbjørn Nilsen Riseth   }
2459566063dSJacob Faibussowitsch   PetscCall(SNESSetWorkVecs(snes, 4));
24692f76d53SAlp Dener 
24748a46eb9SPierre Jolivet   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) PetscCall(SNESSetUpMatrices(snes));
248ad540459SPierre Jolivet   if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_UNPRECONDITIONED;
24992f76d53SAlp Dener 
25060c08b40SPeter Brune   /* set method defaults */
2511efc8c45SPeter Brune   if (qn->scale_type == SNES_QN_SCALE_DEFAULT) {
25260c08b40SPeter Brune     if (qn->type == SNES_QN_BADBROYDEN) {
25360c08b40SPeter Brune       qn->scale_type = SNES_QN_SCALE_NONE;
25460c08b40SPeter Brune     } else {
25592f76d53SAlp Dener       qn->scale_type = SNES_QN_SCALE_SCALAR;
25660c08b40SPeter Brune     }
25760c08b40SPeter Brune   }
2581efc8c45SPeter Brune   if (qn->restart_type == SNES_QN_RESTART_DEFAULT) {
25960c08b40SPeter Brune     if (qn->type == SNES_QN_LBFGS) {
26060c08b40SPeter Brune       qn->restart_type = SNES_QN_RESTART_POWELL;
26160c08b40SPeter Brune     } else {
26260c08b40SPeter Brune       qn->restart_type = SNES_QN_RESTART_PERIODIC;
26360c08b40SPeter Brune     }
26460c08b40SPeter Brune   }
26560c08b40SPeter Brune 
26692f76d53SAlp Dener   /* Set up the LMVM matrix */
26792f76d53SAlp Dener   switch (qn->type) {
26892f76d53SAlp Dener   case SNES_QN_BROYDEN:
2699566063dSJacob Faibussowitsch     PetscCall(MatSetType(qn->B, MATLMVMBROYDEN));
27092f76d53SAlp Dener     qn->scale_type = SNES_QN_SCALE_NONE;
27192f76d53SAlp Dener     break;
27292f76d53SAlp Dener   case SNES_QN_BADBROYDEN:
2739566063dSJacob Faibussowitsch     PetscCall(MatSetType(qn->B, MATLMVMBADBROYDEN));
27492f76d53SAlp Dener     qn->scale_type = SNES_QN_SCALE_NONE;
27592f76d53SAlp Dener     break;
27692f76d53SAlp Dener   default:
2779566063dSJacob Faibussowitsch     PetscCall(MatSetType(qn->B, MATLMVMBFGS));
27892f76d53SAlp Dener     switch (qn->scale_type) {
279d71ae5a4SJacob Faibussowitsch     case SNES_QN_SCALE_NONE:
280d71ae5a4SJacob Faibussowitsch       PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_NONE));
281d71ae5a4SJacob Faibussowitsch       break;
282d71ae5a4SJacob Faibussowitsch     case SNES_QN_SCALE_SCALAR:
283d71ae5a4SJacob Faibussowitsch       PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_SCALAR));
284d71ae5a4SJacob Faibussowitsch       break;
285d71ae5a4SJacob Faibussowitsch     case SNES_QN_SCALE_JACOBIAN:
286d71ae5a4SJacob Faibussowitsch       PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_USER));
287d71ae5a4SJacob Faibussowitsch       break;
28892f76d53SAlp Dener     case SNES_QN_SCALE_DIAGONAL:
28992f76d53SAlp Dener     case SNES_QN_SCALE_DEFAULT:
290d71ae5a4SJacob Faibussowitsch     default:
291d71ae5a4SJacob Faibussowitsch       break;
2928e231d97SPeter Brune     }
29392f76d53SAlp Dener     break;
29492f76d53SAlp Dener   }
2959566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(snes->vec_sol, &n));
2969566063dSJacob Faibussowitsch   PetscCall(VecGetSize(snes->vec_sol, &N));
2979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(qn->B, n, n, N, N));
2989566063dSJacob Faibussowitsch   PetscCall(MatSetUp(qn->B));
2999566063dSJacob Faibussowitsch   PetscCall(MatLMVMReset(qn->B, PETSC_TRUE));
3009566063dSJacob Faibussowitsch   PetscCall(MatLMVMSetHistorySize(qn->B, qn->m));
3019566063dSJacob Faibussowitsch   PetscCall(MatLMVMAllocate(qn->B, snes->vec_sol, snes->vec_func));
3023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3034b11644fSPeter Brune }
3044b11644fSPeter Brune 
305d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESReset_QN(SNES snes)
306d71ae5a4SJacob Faibussowitsch {
3079f83bee8SJed Brown   SNES_QN *qn;
3080adebc6cSBarry Smith 
3094b11644fSPeter Brune   PetscFunctionBegin;
3104b11644fSPeter Brune   if (snes->data) {
3119f83bee8SJed Brown     qn = (SNES_QN *)snes->data;
3129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&qn->B));
3134b11644fSPeter Brune   }
3143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3154b11644fSPeter Brune }
3164b11644fSPeter Brune 
317d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESDestroy_QN(SNES snes)
318d71ae5a4SJacob Faibussowitsch {
3194b11644fSPeter Brune   PetscFunctionBegin;
3209566063dSJacob Faibussowitsch   PetscCall(SNESReset_QN(snes));
3219566063dSJacob Faibussowitsch   PetscCall(PetscFree(snes->data));
3222e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetScaleType_C", NULL));
3232e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetRestartType_C", NULL));
3242e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetType_C", NULL));
3253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3264b11644fSPeter Brune }
3274b11644fSPeter Brune 
328d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetFromOptions_QN(SNES snes, PetscOptionItems *PetscOptionsObject)
329d71ae5a4SJacob Faibussowitsch {
3302150357eSBarry Smith   SNES_QN          *qn = (SNES_QN *)snes->data;
33192f76d53SAlp Dener   PetscBool         flg;
332f1c6b773SPeter Brune   SNESLineSearch    linesearch;
3332150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
3342150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
3351efc8c45SPeter Brune   SNESQNType        qtype = qn->type;
3362150357eSBarry Smith 
3374b11644fSPeter Brune   PetscFunctionBegin;
338d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "SNES QN options");
3399566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_qn_m", "Number of past states saved for L-BFGS methods", "SNESQN", qn->m, &qn->m, NULL));
3409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_qn_powell_gamma", "Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL));
3419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", qn->monflg, &qn->monflg, NULL));
3429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-snes_qn_scale_type", "Scaling type", "SNESQNSetScaleType", SNESQNScaleTypes, (PetscEnum)stype, (PetscEnum *)&stype, &flg));
3439566063dSJacob Faibussowitsch   if (flg) PetscCall(SNESQNSetScaleType(snes, stype));
34488f769c5SPeter Brune 
3459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-snes_qn_restart_type", "Restart type", "SNESQNSetRestartType", SNESQNRestartTypes, (PetscEnum)rtype, (PetscEnum *)&rtype, &flg));
3469566063dSJacob Faibussowitsch   if (flg) PetscCall(SNESQNSetRestartType(snes, rtype));
34788f769c5SPeter Brune 
3489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-snes_qn_type", "Quasi-Newton update type", "", SNESQNTypes, (PetscEnum)qtype, (PetscEnum *)&qtype, &flg));
3499566063dSJacob Faibussowitsch   if (flg) PetscCall(SNESQNSetType(snes, qtype));
3509566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(qn->B));
351d0609cedSBarry Smith   PetscOptionsHeadEnd();
3529e764e56SPeter Brune   if (!snes->linesearch) {
3539566063dSJacob Faibussowitsch     PetscCall(SNESGetLineSearch(snes, &linesearch));
354ec786807SJed Brown     if (!((PetscObject)linesearch)->type_name) {
35560c08b40SPeter Brune       if (qn->type == SNES_QN_LBFGS) {
3569566063dSJacob Faibussowitsch         PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHCP));
35760c08b40SPeter Brune       } else if (qn->type == SNES_QN_BROYDEN) {
3589566063dSJacob Faibussowitsch         PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
35960c08b40SPeter Brune       } else {
3609566063dSJacob Faibussowitsch         PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHL2));
36160c08b40SPeter Brune       }
3629e764e56SPeter Brune     }
363ec786807SJed Brown   }
36448a46eb9SPierre Jolivet   if (qn->monflg) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)snes), &qn->monitor));
3653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3664b11644fSPeter Brune }
3674b11644fSPeter Brune 
368d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer)
369d71ae5a4SJacob Faibussowitsch {
3705cd83419SPeter Brune   SNES_QN  *qn = (SNES_QN *)snes->data;
3715cd83419SPeter Brune   PetscBool iascii;
3725cd83419SPeter Brune 
3735cd83419SPeter Brune   PetscFunctionBegin;
3749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3755cd83419SPeter Brune   if (iascii) {
3769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, restart type is %s, scale type is %s\n", SNESQNTypes[qn->type], SNESQNRestartTypes[qn->restart_type], SNESQNScaleTypes[qn->scale_type]));
37763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Stored subspace size: %" PetscInt_FMT "\n", qn->m));
3785cd83419SPeter Brune   }
3793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3805cd83419SPeter Brune }
38192c02d66SPeter Brune 
3820c777b0cSPeter Brune /*@
383f6dfbefdSBarry Smith     SNESQNSetRestartType - Sets the restart type for `SNESQN`.
3840c777b0cSPeter Brune 
385c3339decSBarry Smith     Logically Collective
3860c777b0cSPeter Brune 
3870c777b0cSPeter Brune     Input Parameters:
3880c777b0cSPeter Brune +   snes - the iterative context
3890c777b0cSPeter Brune -   rtype - restart type
3900c777b0cSPeter Brune 
391f6dfbefdSBarry Smith     Options Database Keys:
3920c777b0cSPeter Brune +   -snes_qn_restart_type <powell,periodic,none> - set the restart type
39384c577daSBarry Smith -   -snes_qn_m <m> - sets the number of stored updates and the restart period for periodic
3940c777b0cSPeter Brune 
3950c777b0cSPeter Brune     Level: intermediate
3960c777b0cSPeter Brune 
397f6dfbefdSBarry Smith     `SNESQNRestartType`s:
398f6dfbefdSBarry Smith +   `SNES_QN_RESTART_NONE` - never restart
399f6dfbefdSBarry Smith .   `SNES_QN_RESTART_POWELL` - restart based upon descent criteria
400f6dfbefdSBarry Smith -   `SNES_QN_RESTART_PERIODIC` - restart after a fixed number of iterations
4010c777b0cSPeter Brune 
402f6dfbefdSBarry Smith .seealso: `SNESQN`, `SNESQNRestartType`, `SNES_QN_RESTART_NONE`, `SNES_QN_RESTART_POWELL`, `SNES_QN_RESTART_PERIODIC`
4030c777b0cSPeter Brune @*/
404d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
405d71ae5a4SJacob Faibussowitsch {
4060c777b0cSPeter Brune   PetscFunctionBegin;
4070c777b0cSPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
408cac4c232SBarry Smith   PetscTryMethod(snes, "SNESQNSetRestartType_C", (SNES, SNESQNRestartType), (snes, rtype));
4093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4100c777b0cSPeter Brune }
4110c777b0cSPeter Brune 
4120c777b0cSPeter Brune /*@
413f6dfbefdSBarry Smith     SNESQNSetScaleType - Sets the scaling type for the inner inverse Jacobian in `SNESQN`.
4140c777b0cSPeter Brune 
415c3339decSBarry Smith     Logically Collective
4160c777b0cSPeter Brune 
4170c777b0cSPeter Brune     Input Parameters:
418f6dfbefdSBarry Smith +   snes - the nonlinear solver context
4190c777b0cSPeter Brune -   stype - scale type
4200c777b0cSPeter Brune 
4213c7db156SBarry Smith     Options Database Key:
42267b8a455SSatish Balay .   -snes_qn_scale_type <diagonal,none,scalar,jacobian> - Scaling type
4230c777b0cSPeter Brune 
4240c777b0cSPeter Brune     Level: intermediate
4250c777b0cSPeter Brune 
426f6dfbefdSBarry Smith     `SNESQNScaleType`s:
427f6dfbefdSBarry Smith +   `SNES_QN_SCALE_NONE` - don't scale the problem
428f6dfbefdSBarry Smith .   `SNES_QN_SCALE_SCALAR` - use Shanno scaling
429f6dfbefdSBarry Smith .   `SNES_QN_SCALE_DIAGONAL` - scale with a diagonalized BFGS formula (see Gilbert and Lemarechal 1989), available
430f6dfbefdSBarry Smith -   `SNES_QN_SCALE_JACOBIAN` - scale by solving a linear system coming from the Jacobian you provided with SNESSetJacobian() computed at the first iteration
431a01a0525SBarry Smith                              of QN and at ever restart.
4320c777b0cSPeter Brune 
433db781477SPatrick Sanan .seealso: `SNES`, `SNESQN`, `SNESLineSearch`, `SNESQNScaleType`, `SNESSetJacobian()`
4340c777b0cSPeter Brune @*/
4350c777b0cSPeter Brune 
436d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
437d71ae5a4SJacob Faibussowitsch {
4380c777b0cSPeter Brune   PetscFunctionBegin;
4390c777b0cSPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
440cac4c232SBarry Smith   PetscTryMethod(snes, "SNESQNSetScaleType_C", (SNES, SNESQNScaleType), (snes, stype));
4413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4420c777b0cSPeter Brune }
4430c777b0cSPeter Brune 
444d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
445d71ae5a4SJacob Faibussowitsch {
4460c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN *)snes->data;
4476e111a19SKarl Rupp 
4480c777b0cSPeter Brune   PetscFunctionBegin;
4490c777b0cSPeter Brune   qn->scale_type = stype;
4507044b745SBarry Smith   if (stype == SNES_QN_SCALE_JACOBIAN) snes->usesksp = PETSC_TRUE;
4513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4520c777b0cSPeter Brune }
4530c777b0cSPeter Brune 
454d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
455d71ae5a4SJacob Faibussowitsch {
4560c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN *)snes->data;
4576e111a19SKarl Rupp 
4580c777b0cSPeter Brune   PetscFunctionBegin;
4590c777b0cSPeter Brune   qn->restart_type = rtype;
4603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4610c777b0cSPeter Brune }
4620c777b0cSPeter Brune 
4631efc8c45SPeter Brune /*@
464f6dfbefdSBarry Smith     SNESQNSetType - Sets the quasi-Newton variant to be used in `SNESQN`.
4651efc8c45SPeter Brune 
466c3339decSBarry Smith     Logically Collective
4671efc8c45SPeter Brune 
4681efc8c45SPeter Brune     Input Parameters:
4691efc8c45SPeter Brune +   snes - the iterative context
4701efc8c45SPeter Brune -   qtype - variant type
4711efc8c45SPeter Brune 
4723c7db156SBarry Smith     Options Database Key:
47367b8a455SSatish Balay .   -snes_qn_type <lbfgs,broyden,badbroyden> - quasi-Newton type
4741efc8c45SPeter Brune 
4751efc8c45SPeter Brune     Level: beginner
4761efc8c45SPeter Brune 
477f6dfbefdSBarry Smith     `SNESQNType`s:
478f6dfbefdSBarry Smith +   `SNES_QN_LBFGS` - LBFGS variant
479f6dfbefdSBarry Smith .   `SNES_QN_BROYDEN` - Broyden variant
480f6dfbefdSBarry Smith -   `SNES_QN_BADBROYDEN` - Bad Broyden variant
4811efc8c45SPeter Brune 
482f6dfbefdSBarry Smith .seealso: `SNESQN`, `SNES_QN_LBFGS`, `SNES_QN_BROYDEN`, `SNES_QN_BADBROYDEN`, `SNESQNType`, `TAOLMVM`, `TAOBLMVM`
4831efc8c45SPeter Brune @*/
4841efc8c45SPeter Brune 
485d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype)
486d71ae5a4SJacob Faibussowitsch {
4871efc8c45SPeter Brune   PetscFunctionBegin;
4881efc8c45SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
489cac4c232SBarry Smith   PetscTryMethod(snes, "SNESQNSetType_C", (SNES, SNESQNType), (snes, qtype));
4903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4911efc8c45SPeter Brune }
4921efc8c45SPeter Brune 
493d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype)
494d71ae5a4SJacob Faibussowitsch {
4951efc8c45SPeter Brune   SNES_QN *qn = (SNES_QN *)snes->data;
4961efc8c45SPeter Brune 
4971efc8c45SPeter Brune   PetscFunctionBegin;
4981efc8c45SPeter Brune   qn->type = qtype;
4993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5001efc8c45SPeter Brune }
5011efc8c45SPeter Brune 
5024b11644fSPeter Brune /*MC
5034b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
5044b11644fSPeter Brune 
505f6dfbefdSBarry Smith       Options Database Keys:
50684c577daSBarry Smith +     -snes_qn_m <m> - Number of past states saved for the L-Broyden methods.
507f6dfbefdSBarry Smith .     -snes_qn_restart_type <powell,periodic,none> - set the restart type
5086bdcc836SBarry Smith .     -snes_qn_powell_gamma - Angle condition for restart.
5091867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
51084c577daSBarry Smith .     -snes_qn_type <lbfgs,broyden,badbroyden> - QN type
51192f76d53SAlp Dener .     -snes_qn_scale_type <diagonal,none,scalar,jacobian> - scaling performed on inner Jacobian
51272835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
51384c577daSBarry Smith -     -snes_qn_monitor - Monitors the quasi-newton Jacobian.
5146cc8130cSPeter Brune 
5156cc8130cSPeter Brune       References:
516606c0280SSatish Balay +   * -   Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995.
517606c0280SSatish Balay .   * -   R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi Newton Matrices and their use in Limited Memory Methods,
5180a8e8854SPeter Brune       Technical Report, Northwestern University, June 1992.
519606c0280SSatish Balay .   * -   Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE
5200a8e8854SPeter Brune       Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
521606c0280SSatish Balay .   * -   Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
5224f02bc6aSBarry Smith        SIAM Review, 57(4), 2015
523606c0280SSatish Balay .   * -   Griewank, Andreas. "Broyden updating, the good and the bad!." Doc. Math (2012): 301-315.
524606c0280SSatish Balay .   * -   Gilbert, Jean Charles, and Claude Lemar{\'e}chal. "Some numerical experiments with variable-storage quasi-Newton algorithms."
52592f76d53SAlp Dener       Mathematical programming 45.1-3 (1989): 407-435.
526606c0280SSatish Balay -   * -   Dener A., Munson T. "Accelerating Limited-Memory Quasi-Newton Convergence for Large-Scale Optimization"
527110fc3b0SBarry Smith       Computational Science - ICCS 2019. ICCS 2019. Lecture Notes in Computer Science, vol 11538. Springer, Cham
5284b11644fSPeter Brune 
5294b11644fSPeter Brune       Level: beginner
5304b11644fSPeter Brune 
531f6dfbefdSBarry Smith       Notes:
532f6dfbefdSBarry Smith       This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
533f6dfbefdSBarry Smith       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
534f6dfbefdSBarry Smith       updates.
5356cc8130cSPeter Brune 
536f6dfbefdSBarry Smith       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
537f6dfbefdSBarry Smith       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
538f6dfbefdSBarry Smith       iteration as the current iteration's values when constructing the approximate Jacobian.  The second, composed,
539f6dfbefdSBarry Smith       perturbs the problem the Jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
540f6dfbefdSBarry Smith 
541f6dfbefdSBarry Smith       Uses left nonlinear preconditioning by default.
542f6dfbefdSBarry Smith 
543f6dfbefdSBarry Smith .seealso: `SNESQNRestartType`, `SNESQNSetRestartType()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONLS`, `SNESNEWTONTR`,
544f6dfbefdSBarry Smith           `SNESQNScaleType`, `SNESQNSetScaleType()`, `SNESQNSetType`, `SNESQNSetType()`
5454b11644fSPeter Brune M*/
546d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
547d71ae5a4SJacob Faibussowitsch {
5489f83bee8SJed Brown   SNES_QN    *qn;
54992f76d53SAlp Dener   const char *optionsprefix;
5504b11644fSPeter Brune 
5514b11644fSPeter Brune   PetscFunctionBegin;
5524b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
5534b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
5544b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
5554b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
5565cd83419SPeter Brune   snes->ops->view           = SNESView_QN;
5574b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
5584b11644fSPeter Brune 
559efd4aadfSBarry Smith   snes->npcside = PC_LEFT;
56047f26062SPeter Brune 
561efd4aadfSBarry Smith   snes->usesnpc = PETSC_TRUE;
56242f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
56342f4f86dSBarry Smith 
5644fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
5654fc747eaSLawrence Mitchell 
56688976e71SPeter Brune   if (!snes->tolerancesset) {
5670e444f03SPeter Brune     snes->max_funcs = 30000;
5680e444f03SPeter Brune     snes->max_its   = 10000;
56988976e71SPeter Brune   }
5700e444f03SPeter Brune 
5714dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&qn));
5724b11644fSPeter Brune   snes->data       = (void *)qn;
5730ecc9e1dSPeter Brune   qn->m            = 10;
574b21d5a53SPeter Brune   qn->scaling      = 1.0;
5750298fd71SBarry Smith   qn->monitor      = NULL;
57692f76d53SAlp Dener   qn->monflg       = PETSC_FALSE;
577b8840d6bSPeter Brune   qn->powell_gamma = 0.9999;
57860c08b40SPeter Brune   qn->scale_type   = SNES_QN_SCALE_DEFAULT;
57960c08b40SPeter Brune   qn->restart_type = SNES_QN_RESTART_DEFAULT;
580b8840d6bSPeter Brune   qn->type         = SNES_QN_LBFGS;
581ea630c6eSPeter Brune 
5829566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)snes), &qn->B));
5839566063dSJacob Faibussowitsch   PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
5849566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(qn->B, optionsprefix));
58592f76d53SAlp Dener 
5869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetScaleType_C", SNESQNSetScaleType_QN));
5879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetRestartType_C", SNESQNSetRestartType_QN));
5889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetType_C", SNESQNSetType_QN));
5893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5904b11644fSPeter Brune }
591