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 2306594da7SStefano Zampini static PetscErrorCode SNESQNGetMatrix_Private(SNES snes, Mat *B) 2406594da7SStefano Zampini { 2506594da7SStefano Zampini SNES_QN *qn = (SNES_QN *)snes->data; 2606594da7SStefano Zampini const char *optionsprefix; 2706594da7SStefano Zampini 2806594da7SStefano Zampini PetscFunctionBegin; 2906594da7SStefano Zampini if (!qn->B) { 3006594da7SStefano Zampini PetscCall(MatCreate(PetscObjectComm((PetscObject)snes), &qn->B)); 3106594da7SStefano Zampini PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix)); 3206594da7SStefano Zampini PetscCall(MatSetOptionsPrefix(qn->B, optionsprefix)); 3306594da7SStefano Zampini PetscCall(MatAppendOptionsPrefix(qn->B, "qn_")); 3406594da7SStefano Zampini switch (qn->type) { 3506594da7SStefano Zampini case SNES_QN_BROYDEN: 3606594da7SStefano Zampini PetscCall(MatSetType(qn->B, MATLMVMBROYDEN)); 3706594da7SStefano Zampini qn->scale_type = SNES_QN_SCALE_NONE; 3806594da7SStefano Zampini break; 3906594da7SStefano Zampini case SNES_QN_BADBROYDEN: 4006594da7SStefano Zampini PetscCall(MatSetType(qn->B, MATLMVMBADBROYDEN)); 4106594da7SStefano Zampini qn->scale_type = SNES_QN_SCALE_NONE; 4206594da7SStefano Zampini break; 4306594da7SStefano Zampini default: 4406594da7SStefano Zampini PetscCall(MatSetType(qn->B, MATLMVMBFGS)); 4506594da7SStefano Zampini switch (qn->scale_type) { 4606594da7SStefano Zampini case SNES_QN_SCALE_NONE: 4706594da7SStefano Zampini PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_NONE)); 4806594da7SStefano Zampini break; 4906594da7SStefano Zampini case SNES_QN_SCALE_SCALAR: 5006594da7SStefano Zampini case SNES_QN_SCALE_DEFAULT: 5106594da7SStefano Zampini PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_SCALAR)); 5206594da7SStefano Zampini break; 5306594da7SStefano Zampini case SNES_QN_SCALE_JACOBIAN: 5406594da7SStefano Zampini PetscCall(MatLMVMSymBroydenSetScaleType(qn->B, MAT_LMVM_SYMBROYDEN_SCALE_USER)); 5506594da7SStefano Zampini break; 5606594da7SStefano Zampini case SNES_QN_SCALE_DIAGONAL: 5706594da7SStefano Zampini default: 5806594da7SStefano Zampini break; 5906594da7SStefano Zampini } 6006594da7SStefano Zampini break; 6106594da7SStefano Zampini } 6206594da7SStefano Zampini } 6306594da7SStefano Zampini *B = qn->B; 6406594da7SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 6506594da7SStefano Zampini } 6606594da7SStefano Zampini 67d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSolve_QN(SNES snes) 68d71ae5a4SJacob Faibussowitsch { 699f83bee8SJed Brown SNES_QN *qn = (SNES_QN *)snes->data; 7006594da7SStefano Zampini Vec X, F, W; 7147f26062SPeter Brune Vec Y, D, Dold; 72b8840d6bSPeter Brune PetscInt i, i_r; 734279555eSSatish Balay PetscReal fnorm, xnorm, ynorm; 74422a814eSBarry Smith SNESLineSearchReason lssucceed; 7506594da7SStefano Zampini PetscBool badstep, powell, periodic, restart; 761c6523dcSPeter Brune PetscScalar DolddotD, DolddotDold; 77b7281c8aSPeter Brune SNESConvergedReason reason; 784279555eSSatish Balay #if defined(PETSC_USE_INFO) 794279555eSSatish Balay PetscReal gnorm; 804279555eSSatish Balay #endif 810ecc9e1dSPeter Brune 826e111a19SKarl Rupp PetscFunctionBegin; 830b121fc5SBarry 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); 84c579b300SPatrick Farrell 859566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite)); 869f3a0142SPeter Brune F = snes->vec_func; /* residual vector */ 873af51624SPeter Brune Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 88b8840d6bSPeter Brune X = snes->vec_sol; /* solution vector */ 893af51624SPeter Brune 9006594da7SStefano Zampini /* directions */ 9106594da7SStefano Zampini W = snes->work[0]; 92335fb975SPeter Brune D = snes->work[1]; 93335fb975SPeter Brune Dold = snes->work[2]; 944b11644fSPeter Brune 954b11644fSPeter Brune snes->reason = SNES_CONVERGED_ITERATING; 964b11644fSPeter Brune 979566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 984b11644fSPeter Brune snes->iter = 0; 994b11644fSPeter Brune snes->norm = 0.; 1009566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 10147f26062SPeter Brune 102efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { 10306594da7SStefano Zampini /* we need to sample the preconditioned function only once here, 10406594da7SStefano Zampini since linesearch will always use the preconditioned function */ 1059566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes, X, NULL, F)); 1069566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 10706594da7SStefano Zampini if (reason < 0 && reason != SNES_DIVERGED_MAX_IT && reason != SNES_DIVERGED_TR_DELTA) { 108b7281c8aSPeter Brune snes->reason = SNES_DIVERGED_INNER; 1093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 110b7281c8aSPeter Brune } 11147f26062SPeter Brune } else { 11206594da7SStefano Zampini if (!snes->vec_func_init_set) PetscCall(SNESComputeFunction(snes, X, F)); 11306594da7SStefano Zampini else snes->vec_func_init_set = PETSC_FALSE; 11406594da7SStefano Zampini } 1159566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); 116422a814eSBarry Smith SNESCheckFunctionNorm(snes, fnorm); 117b28a06ddSPeter Brune 1189566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 1194b11644fSPeter Brune snes->norm = fnorm; 1209566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 1219566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0)); 1229566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, 0, fnorm)); 1234b11644fSPeter Brune 1244b11644fSPeter Brune /* test convergence */ 1252d157150SStefano Zampini PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm)); 1263ba16761SJacob Faibussowitsch if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 12770d3b23bSPeter Brune 12806594da7SStefano Zampini restart = PETSC_TRUE; 12906594da7SStefano Zampini for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 13006594da7SStefano Zampini PetscScalar gdx; 13106594da7SStefano Zampini 13206594da7SStefano Zampini /* general purpose update */ 13306594da7SStefano Zampini PetscTryTypeMethod(snes, update, snes->iter); 13406594da7SStefano Zampini 13506594da7SStefano Zampini if (snes->npc) { 13606594da7SStefano Zampini if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 13706594da7SStefano Zampini PetscCall(SNESApplyNPC(snes, X, F, D)); 13806594da7SStefano Zampini PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 13906594da7SStefano Zampini if (reason < 0 && reason != SNES_DIVERGED_MAX_IT && reason != SNES_DIVERGED_TR_DELTA) { 14006594da7SStefano Zampini snes->reason = SNES_DIVERGED_INNER; 14106594da7SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 14206594da7SStefano Zampini } 14306594da7SStefano Zampini } else if (snes->npcside == PC_RIGHT) { 1449566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, X, 0, 0)); 1459566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes->npc, snes->vec_rhs, X)); 1469566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, X, 0, 0)); 1479566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 14806594da7SStefano Zampini if (reason < 0 && reason != SNES_DIVERGED_MAX_IT && reason != SNES_DIVERGED_TR_DELTA) { 149ddd40ce5SPeter Brune snes->reason = SNES_DIVERGED_INNER; 1503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 151ddd40ce5SPeter Brune } 1529566063dSJacob Faibussowitsch PetscCall(SNESGetNPCFunction(snes, F, &fnorm)); 1539566063dSJacob Faibussowitsch PetscCall(VecCopy(F, D)); 15406594da7SStefano Zampini } else { 15506594da7SStefano Zampini PetscCall(VecCopy(F, D)); 15606594da7SStefano Zampini } 15706594da7SStefano Zampini } else { 15806594da7SStefano Zampini PetscCall(VecCopy(F, D)); 1593cf07b75SPeter Brune } 1603cf07b75SPeter Brune 161f8e15203SPeter Brune /* scale the initial update */ 16206594da7SStefano Zampini if (qn->scale_type == SNES_QN_SCALE_JACOBIAN && restart) { 1639566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre)); 16407b62357SFande Kong SNESCheckJacobianDomainerror(snes); 1659566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian_pre)); 1669566063dSJacob Faibussowitsch PetscCall(MatLMVMSetJ0KSP(qn->B, snes->ksp)); 1670ecc9e1dSPeter Brune } 1680ecc9e1dSPeter Brune 16992f76d53SAlp Dener /* update QN approx and calculate step */ 1709566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(qn->B, X, D)); 1719566063dSJacob Faibussowitsch PetscCall(MatSolve(qn->B, D, Y)); 17206594da7SStefano Zampini PetscCall(VecDot(F, Y, &gdx)); 17306594da7SStefano Zampini if (PetscAbsScalar(gdx) <= 0) { 17406594da7SStefano Zampini /* Step is not descent or solve was not successful 17506594da7SStefano Zampini Use steepest descent direction */ 17606594da7SStefano Zampini PetscCall(VecCopy(F, Y)); 17706594da7SStefano Zampini PetscCall(MatLMVMReset(qn->B, PETSC_FALSE)); 17806594da7SStefano Zampini } 17992f76d53SAlp Dener 18070d3b23bSPeter Brune /* line search for lambda */ 1819371c9d4SSatish Balay ynorm = 1; 1824279555eSSatish Balay #if defined(PETSC_USE_INFO) 1839371c9d4SSatish Balay gnorm = fnorm; 1844279555eSSatish Balay #endif 1859566063dSJacob Faibussowitsch PetscCall(VecCopy(D, Dold)); 1869566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y)); 1879f3a0142SPeter Brune if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 1889566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 1899566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm)); 19092f76d53SAlp Dener badstep = PETSC_FALSE; 191422a814eSBarry Smith if (lssucceed) { 1929f3a0142SPeter Brune if (++snes->numFailures >= snes->maxFailures) { 1939f3a0142SPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 1949f3a0142SPeter Brune break; 1959f3a0142SPeter Brune } 19692f76d53SAlp Dener badstep = PETSC_TRUE; 1970ecc9e1dSPeter Brune } 1983af51624SPeter Brune 19988d374b2SPeter Brune /* convergence monitoring */ 2009566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed)); 201b21d5a53SPeter Brune 20206594da7SStefano Zampini PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 20306594da7SStefano Zampini snes->iter = i + 1; 20471dbe336SPeter Brune snes->norm = fnorm; 205c1e67a49SFande Kong snes->xnorm = xnorm; 206c1e67a49SFande Kong snes->ynorm = ynorm; 20706594da7SStefano Zampini PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 208360c497dSPeter Brune 2099566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, snes->iter)); 21092f76d53SAlp Dener 2114b11644fSPeter Brune /* set parameter for default relative tolerance convergence test */ 2122d157150SStefano Zampini PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm)); 2132d157150SStefano Zampini PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 2143ba16761SJacob Faibussowitsch if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 21506594da7SStefano Zampini 216efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 2179566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes, X, F, D)); 2189566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 21906594da7SStefano Zampini if (reason < 0 && reason != SNES_DIVERGED_MAX_IT && reason != SNES_DIVERGED_TR_DELTA) { 220b7281c8aSPeter Brune snes->reason = SNES_DIVERGED_INNER; 2213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 222b7281c8aSPeter Brune } 22388d374b2SPeter Brune } else { 2249566063dSJacob Faibussowitsch PetscCall(VecCopy(F, D)); 22588d374b2SPeter Brune } 22601fe78eaSStefano Zampini 22792f76d53SAlp Dener /* restart conditions */ 2280c777b0cSPeter Brune powell = PETSC_FALSE; 2296bdcc836SBarry Smith if (qn->restart_type == SNES_QN_RESTART_POWELL && i_r > 1) { 2306bdcc836SBarry Smith /* check restart by Powell's Criterion: |F^T H_0 Fold| > powell_gamma * |Fold^T H_0 Fold| */ 23123c918e7SPeter Brune if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 232574a8f54SStefano Zampini PetscCall(MatMult(snes->jacobian, Dold, W)); 23323c918e7SPeter Brune } else { 2349566063dSJacob Faibussowitsch PetscCall(VecCopy(Dold, W)); 23523c918e7SPeter Brune } 2369566063dSJacob Faibussowitsch PetscCall(VecDotBegin(W, Dold, &DolddotDold)); 2379566063dSJacob Faibussowitsch PetscCall(VecDotBegin(W, D, &DolddotD)); 2389566063dSJacob Faibussowitsch PetscCall(VecDotEnd(W, Dold, &DolddotDold)); 2399566063dSJacob Faibussowitsch PetscCall(VecDotEnd(W, D, &DolddotD)); 2400c777b0cSPeter Brune if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma * PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE; 2410c777b0cSPeter Brune } 2420c777b0cSPeter Brune periodic = PETSC_FALSE; 243b8840d6bSPeter Brune if (qn->restart_type == SNES_QN_RESTART_PERIODIC) { 244b8840d6bSPeter Brune if (i_r > qn->m - 1) periodic = PETSC_TRUE; 2450c777b0cSPeter Brune } 24606594da7SStefano Zampini 2470c777b0cSPeter Brune /* restart if either powell or periodic restart is satisfied. */ 24806594da7SStefano Zampini restart = PETSC_FALSE; 24992f76d53SAlp Dener if (badstep || powell || periodic) { 25006594da7SStefano Zampini restart = PETSC_TRUE; 25192f76d53SAlp Dener if (qn->monflg) { 2529566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIAddTab(qn->monitor, ((PetscObject)snes)->tablevel + 2)); 2536bdcc836SBarry Smith if (powell) { 25463a3b9bcSJacob 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)); 2556bdcc836SBarry Smith } else { 25663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(qn->monitor, "Periodic restart! i_r = %" PetscInt_FMT "\n", i_r)); 2576bdcc836SBarry Smith } 2589566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIISubtractTab(qn->monitor, ((PetscObject)snes)->tablevel + 2)); 2595ba6227bSPeter Brune } 2605ba6227bSPeter Brune i_r = -1; 2619566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(qn->B, PETSC_FALSE)); 2620ecc9e1dSPeter Brune } 2635ba6227bSPeter Brune } 2643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2654b11644fSPeter Brune } 2664b11644fSPeter Brune 267d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetUp_QN(SNES snes) 268d71ae5a4SJacob Faibussowitsch { 2699f83bee8SJed Brown SNES_QN *qn = (SNES_QN *)snes->data; 270fced5a79SAsbjørn Nilsen Riseth DM dm; 27192f76d53SAlp Dener PetscInt n, N; 272335fb975SPeter Brune 2734b11644fSPeter Brune PetscFunctionBegin; 274fced5a79SAsbjørn Nilsen Riseth if (!snes->vec_sol) { 2759566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 2769566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(dm, &snes->vec_sol)); 277fced5a79SAsbjørn Nilsen Riseth } 27806594da7SStefano Zampini PetscCall(SNESSetWorkVecs(snes, 3)); 27906594da7SStefano Zampini PetscCall(SNESQNGetMatrix_Private(snes, &qn->B)); 28092f76d53SAlp Dener 28148a46eb9SPierre Jolivet if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) PetscCall(SNESSetUpMatrices(snes)); 28206594da7SStefano Zampini if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED; 28392f76d53SAlp Dener 28460c08b40SPeter Brune /* set method defaults */ 2851efc8c45SPeter Brune if (qn->scale_type == SNES_QN_SCALE_DEFAULT) { 28660c08b40SPeter Brune if (qn->type == SNES_QN_BADBROYDEN) { 28760c08b40SPeter Brune qn->scale_type = SNES_QN_SCALE_NONE; 28860c08b40SPeter Brune } else { 28992f76d53SAlp Dener qn->scale_type = SNES_QN_SCALE_SCALAR; 29060c08b40SPeter Brune } 29160c08b40SPeter Brune } 2921efc8c45SPeter Brune if (qn->restart_type == SNES_QN_RESTART_DEFAULT) { 29360c08b40SPeter Brune if (qn->type == SNES_QN_LBFGS) { 29460c08b40SPeter Brune qn->restart_type = SNES_QN_RESTART_POWELL; 29560c08b40SPeter Brune } else { 29660c08b40SPeter Brune qn->restart_type = SNES_QN_RESTART_PERIODIC; 29760c08b40SPeter Brune } 29860c08b40SPeter Brune } 29992f76d53SAlp Dener /* Set up the LMVM matrix */ 30006594da7SStefano Zampini PetscCall(SNESQNGetMatrix_Private(snes, &qn->B)); 3019566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(snes->vec_sol, &n)); 3029566063dSJacob Faibussowitsch PetscCall(VecGetSize(snes->vec_sol, &N)); 3039566063dSJacob Faibussowitsch PetscCall(MatSetSizes(qn->B, n, n, N, N)); 3049566063dSJacob Faibussowitsch PetscCall(MatSetUp(qn->B)); 3059566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(qn->B, PETSC_TRUE)); 3069566063dSJacob Faibussowitsch PetscCall(MatLMVMSetHistorySize(qn->B, qn->m)); 3079566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(qn->B, snes->vec_sol, snes->vec_func)); 3083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3094b11644fSPeter Brune } 3104b11644fSPeter Brune 311d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESReset_QN(SNES snes) 312d71ae5a4SJacob Faibussowitsch { 31306594da7SStefano Zampini SNES_QN *qn = (SNES_QN *)snes->data; 3140adebc6cSBarry Smith 3154b11644fSPeter Brune PetscFunctionBegin; 3169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&qn->B)); 3173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3184b11644fSPeter Brune } 3194b11644fSPeter Brune 320d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESDestroy_QN(SNES snes) 321d71ae5a4SJacob Faibussowitsch { 3224b11644fSPeter Brune PetscFunctionBegin; 3239566063dSJacob Faibussowitsch PetscCall(SNESReset_QN(snes)); 3249566063dSJacob Faibussowitsch PetscCall(PetscFree(snes->data)); 3252e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetScaleType_C", NULL)); 3262e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetRestartType_C", NULL)); 3272e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetType_C", NULL)); 3283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3294b11644fSPeter Brune } 3304b11644fSPeter Brune 331d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetFromOptions_QN(SNES snes, PetscOptionItems *PetscOptionsObject) 332d71ae5a4SJacob Faibussowitsch { 3332150357eSBarry Smith SNES_QN *qn = (SNES_QN *)snes->data; 33492f76d53SAlp Dener PetscBool flg; 335f1c6b773SPeter Brune SNESLineSearch linesearch; 3362150357eSBarry Smith SNESQNRestartType rtype = qn->restart_type; 3372150357eSBarry Smith SNESQNScaleType stype = qn->scale_type; 3381efc8c45SPeter Brune SNESQNType qtype = qn->type; 3392150357eSBarry Smith 3404b11644fSPeter Brune PetscFunctionBegin; 341d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "SNES QN options"); 3429566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_qn_m", "Number of past states saved for L-BFGS methods", "SNESQN", qn->m, &qn->m, NULL)); 3439566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_qn_powell_gamma", "Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL)); 3449566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", qn->monflg, &qn->monflg, NULL)); 3459566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-snes_qn_scale_type", "Scaling type", "SNESQNSetScaleType", SNESQNScaleTypes, (PetscEnum)stype, (PetscEnum *)&stype, &flg)); 3469566063dSJacob Faibussowitsch if (flg) PetscCall(SNESQNSetScaleType(snes, stype)); 34788f769c5SPeter Brune 3489566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-snes_qn_restart_type", "Restart type", "SNESQNSetRestartType", SNESQNRestartTypes, (PetscEnum)rtype, (PetscEnum *)&rtype, &flg)); 3499566063dSJacob Faibussowitsch if (flg) PetscCall(SNESQNSetRestartType(snes, rtype)); 35088f769c5SPeter Brune 3519566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-snes_qn_type", "Quasi-Newton update type", "", SNESQNTypes, (PetscEnum)qtype, (PetscEnum *)&qtype, &flg)); 3529566063dSJacob Faibussowitsch if (flg) PetscCall(SNESQNSetType(snes, qtype)); 353d0609cedSBarry Smith PetscOptionsHeadEnd(); 35406594da7SStefano Zampini PetscCall(SNESQNGetMatrix_Private(snes, &qn->B)); 35506594da7SStefano Zampini PetscCall(MatSetFromOptions(qn->B)); 3569e764e56SPeter Brune if (!snes->linesearch) { 3579566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 358ec786807SJed Brown if (!((PetscObject)linesearch)->type_name) { 35960c08b40SPeter Brune if (qn->type == SNES_QN_LBFGS) { 3609566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHCP)); 36160c08b40SPeter Brune } else if (qn->type == SNES_QN_BROYDEN) { 3629566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC)); 36360c08b40SPeter Brune } else { 3649566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHL2)); 36560c08b40SPeter Brune } 3669e764e56SPeter Brune } 367ec786807SJed Brown } 36848a46eb9SPierre Jolivet if (qn->monflg) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)snes), &qn->monitor)); 3693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3704b11644fSPeter Brune } 3714b11644fSPeter Brune 372d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer) 373d71ae5a4SJacob Faibussowitsch { 3745cd83419SPeter Brune SNES_QN *qn = (SNES_QN *)snes->data; 3755cd83419SPeter Brune PetscBool iascii; 3765cd83419SPeter Brune 3775cd83419SPeter Brune PetscFunctionBegin; 3789566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 3795cd83419SPeter Brune if (iascii) { 3809566063dSJacob 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])); 38163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Stored subspace size: %" PetscInt_FMT "\n", qn->m)); 38206594da7SStefano Zampini PetscCall(MatView(qn->B, viewer)); 3835cd83419SPeter Brune } 3843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3855cd83419SPeter Brune } 38692c02d66SPeter Brune 3870c777b0cSPeter Brune /*@ 388f6dfbefdSBarry Smith SNESQNSetRestartType - Sets the restart type for `SNESQN`. 3890c777b0cSPeter Brune 390c3339decSBarry Smith Logically Collective 3910c777b0cSPeter Brune 3920c777b0cSPeter Brune Input Parameters: 3930c777b0cSPeter Brune + snes - the iterative context 394ceaaa498SBarry Smith - rtype - restart type, see `SNESQNRestartType` 3950c777b0cSPeter Brune 396f6dfbefdSBarry Smith Options Database Keys: 3970c777b0cSPeter Brune + -snes_qn_restart_type <powell,periodic,none> - set the restart type 39884c577daSBarry Smith - -snes_qn_m <m> - sets the number of stored updates and the restart period for periodic 3990c777b0cSPeter Brune 4000c777b0cSPeter Brune Level: intermediate 4010c777b0cSPeter Brune 402420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESQN`, `SNESQNRestartType`, `SNES_QN_RESTART_NONE`, `SNES_QN_RESTART_POWELL`, `SNES_QN_RESTART_PERIODIC`, 403ceaaa498SBarry Smith `SNESQNType`, `SNESQNScaleType` 4040c777b0cSPeter Brune @*/ 405d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype) 406d71ae5a4SJacob Faibussowitsch { 4070c777b0cSPeter Brune PetscFunctionBegin; 4080c777b0cSPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 409cac4c232SBarry Smith PetscTryMethod(snes, "SNESQNSetRestartType_C", (SNES, SNESQNRestartType), (snes, rtype)); 4103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4110c777b0cSPeter Brune } 4120c777b0cSPeter Brune 4130c777b0cSPeter Brune /*@ 414f6dfbefdSBarry Smith SNESQNSetScaleType - Sets the scaling type for the inner inverse Jacobian in `SNESQN`. 4150c777b0cSPeter Brune 416c3339decSBarry Smith Logically Collective 4170c777b0cSPeter Brune 4180c777b0cSPeter Brune Input Parameters: 419f6dfbefdSBarry Smith + snes - the nonlinear solver context 420ceaaa498SBarry Smith - stype - scale type, see `SNESQNScaleType` 4210c777b0cSPeter Brune 4223c7db156SBarry Smith Options Database Key: 42367b8a455SSatish Balay . -snes_qn_scale_type <diagonal,none,scalar,jacobian> - Scaling type 4240c777b0cSPeter Brune 4250c777b0cSPeter Brune Level: intermediate 4260c777b0cSPeter Brune 427420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESQN`, `SNESLineSearch`, `SNESQNScaleType`, `SNESSetJacobian()`, `SNESQNType`, `SNESQNRestartType` 4280c777b0cSPeter Brune @*/ 429d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype) 430d71ae5a4SJacob Faibussowitsch { 4310c777b0cSPeter Brune PetscFunctionBegin; 4320c777b0cSPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 433cac4c232SBarry Smith PetscTryMethod(snes, "SNESQNSetScaleType_C", (SNES, SNESQNScaleType), (snes, stype)); 4343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4350c777b0cSPeter Brune } 4360c777b0cSPeter Brune 43766976f2fSJacob Faibussowitsch static PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype) 438d71ae5a4SJacob Faibussowitsch { 4390c777b0cSPeter Brune SNES_QN *qn = (SNES_QN *)snes->data; 4406e111a19SKarl Rupp 4410c777b0cSPeter Brune PetscFunctionBegin; 4420c777b0cSPeter Brune qn->scale_type = stype; 4437044b745SBarry Smith if (stype == SNES_QN_SCALE_JACOBIAN) snes->usesksp = PETSC_TRUE; 4443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4450c777b0cSPeter Brune } 4460c777b0cSPeter Brune 44766976f2fSJacob Faibussowitsch static PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype) 448d71ae5a4SJacob Faibussowitsch { 4490c777b0cSPeter Brune SNES_QN *qn = (SNES_QN *)snes->data; 4506e111a19SKarl Rupp 4510c777b0cSPeter Brune PetscFunctionBegin; 4520c777b0cSPeter Brune qn->restart_type = rtype; 4533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4540c777b0cSPeter Brune } 4550c777b0cSPeter Brune 4561efc8c45SPeter Brune /*@ 457f6dfbefdSBarry Smith SNESQNSetType - Sets the quasi-Newton variant to be used in `SNESQN`. 4581efc8c45SPeter Brune 459c3339decSBarry Smith Logically Collective 4601efc8c45SPeter Brune 4611efc8c45SPeter Brune Input Parameters: 4621efc8c45SPeter Brune + snes - the iterative context 463ceaaa498SBarry Smith - qtype - variant type, see `SNESQNType` 4641efc8c45SPeter Brune 4653c7db156SBarry Smith Options Database Key: 46667b8a455SSatish Balay . -snes_qn_type <lbfgs,broyden,badbroyden> - quasi-Newton type 4671efc8c45SPeter Brune 468ceaaa498SBarry Smith Level: intermediate 4691efc8c45SPeter Brune 470420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESQN`, `SNES_QN_LBFGS`, `SNES_QN_BROYDEN`, `SNES_QN_BADBROYDEN`, `SNESQNType`, `SNESQNScaleType`, `TAOLMVM`, `TAOBLMVM` 4711efc8c45SPeter Brune @*/ 472d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype) 473d71ae5a4SJacob Faibussowitsch { 4741efc8c45SPeter Brune PetscFunctionBegin; 4751efc8c45SPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 476cac4c232SBarry Smith PetscTryMethod(snes, "SNESQNSetType_C", (SNES, SNESQNType), (snes, qtype)); 4773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4781efc8c45SPeter Brune } 4791efc8c45SPeter Brune 48066976f2fSJacob Faibussowitsch static PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype) 481d71ae5a4SJacob Faibussowitsch { 4821efc8c45SPeter Brune SNES_QN *qn = (SNES_QN *)snes->data; 4831efc8c45SPeter Brune 4841efc8c45SPeter Brune PetscFunctionBegin; 4851efc8c45SPeter Brune qn->type = qtype; 4863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4871efc8c45SPeter Brune } 4881efc8c45SPeter Brune 4894b11644fSPeter Brune /*MC 4904b11644fSPeter Brune SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems. 4914b11644fSPeter Brune 492f6dfbefdSBarry Smith Options Database Keys: 49384c577daSBarry Smith + -snes_qn_m <m> - Number of past states saved for the L-Broyden methods. 494f6dfbefdSBarry Smith . -snes_qn_restart_type <powell,periodic,none> - set the restart type 4956bdcc836SBarry Smith . -snes_qn_powell_gamma - Angle condition for restart. 4961867fe5bSPeter Brune . -snes_qn_powell_descent - Descent condition for restart. 49784c577daSBarry Smith . -snes_qn_type <lbfgs,broyden,badbroyden> - QN type 49892f76d53SAlp Dener . -snes_qn_scale_type <diagonal,none,scalar,jacobian> - scaling performed on inner Jacobian 49972835e02SPeter Brune . -snes_linesearch_type <cp, l2, basic> - Type of line search. 50084c577daSBarry Smith - -snes_qn_monitor - Monitors the quasi-newton Jacobian. 5016cc8130cSPeter Brune 5024b11644fSPeter Brune Level: beginner 5034b11644fSPeter Brune 504f6dfbefdSBarry Smith Notes: 5051d27aa22SBarry Smith This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of $F(x) = b$ using 5061d27aa22SBarry Smith previous change in $F(x)$ and $x$ to form the approximate inverse Jacobian using a series of multiplicative rank-one 507f6dfbefdSBarry Smith updates. 5086cc8130cSPeter Brune 509f6dfbefdSBarry Smith When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied. The first of 510f6dfbefdSBarry Smith these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this 511f6dfbefdSBarry Smith iteration as the current iteration's values when constructing the approximate Jacobian. The second, composed, 5121d27aa22SBarry Smith perturbs the problem the Jacobian represents to be $P(x, b) - x = 0 $, where $P(x, b)$ is the preconditioner. 513f6dfbefdSBarry Smith 514f6dfbefdSBarry Smith Uses left nonlinear preconditioning by default. 515f6dfbefdSBarry Smith 5161d27aa22SBarry Smith See {cite}`byrd1994representations`, {cite}`kelley95`, {cite}`brown1985experiments`, {cite}`griewank2012broyden`, {cite}`gilbert1989some`, 5171d27aa22SBarry Smith {cite}`dener2019accelerating`, and {cite}`bruneknepleysmithtu15` 518420bcc1bSBarry Smith 519420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESQNRestartType`, `SNESQNSetRestartType()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONLS`, `SNESNEWTONTR`, 520420bcc1bSBarry Smith `SNESQNScaleType`, `SNESQNSetScaleType()`, `SNESQNType`, `SNESQNSetType()` 5214b11644fSPeter Brune M*/ 522d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes) 523d71ae5a4SJacob Faibussowitsch { 5249f83bee8SJed Brown SNES_QN *qn; 5254b11644fSPeter Brune 5264b11644fSPeter Brune PetscFunctionBegin; 5274b11644fSPeter Brune snes->ops->setup = SNESSetUp_QN; 5284b11644fSPeter Brune snes->ops->solve = SNESSolve_QN; 5294b11644fSPeter Brune snes->ops->destroy = SNESDestroy_QN; 5304b11644fSPeter Brune snes->ops->setfromoptions = SNESSetFromOptions_QN; 5315cd83419SPeter Brune snes->ops->view = SNESView_QN; 5324b11644fSPeter Brune snes->ops->reset = SNESReset_QN; 5334b11644fSPeter Brune 534efd4aadfSBarry Smith snes->npcside = PC_LEFT; 53547f26062SPeter Brune 536efd4aadfSBarry Smith snes->usesnpc = PETSC_TRUE; 53742f4f86dSBarry Smith snes->usesksp = PETSC_FALSE; 53842f4f86dSBarry Smith 5394fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 5404fc747eaSLawrence Mitchell 541*77e5a1f9SBarry Smith PetscCall(SNESParametersInitialize(snes)); 542*77e5a1f9SBarry Smith PetscObjectParameterSetDefault(snes, max_funcs, 30000); 543*77e5a1f9SBarry Smith PetscObjectParameterSetDefault(snes, max_its, 10000); 5440e444f03SPeter Brune 5454dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&qn)); 5464b11644fSPeter Brune snes->data = (void *)qn; 5470ecc9e1dSPeter Brune qn->m = 10; 548b21d5a53SPeter Brune qn->scaling = 1.0; 5490298fd71SBarry Smith qn->monitor = NULL; 55092f76d53SAlp Dener qn->monflg = PETSC_FALSE; 551b8840d6bSPeter Brune qn->powell_gamma = 0.9999; 55260c08b40SPeter Brune qn->scale_type = SNES_QN_SCALE_DEFAULT; 55360c08b40SPeter Brune qn->restart_type = SNES_QN_RESTART_DEFAULT; 554b8840d6bSPeter Brune qn->type = SNES_QN_LBFGS; 555ea630c6eSPeter Brune 5569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetScaleType_C", SNESQNSetScaleType_QN)); 5579566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetRestartType_C", SNESQNSetRestartType_QN)); 5589566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESQNSetType_C", SNESQNSetType_QN)); 5593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5604b11644fSPeter Brune } 561