1 #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/ 2 3 #define H(i,j) qn->dXdFmat[i*qn->m + j] 4 5 const char *const SNESQNScaleTypes[] = {"DEFAULT","NONE","SHANNO","LINESEARCH","JACOBIAN","SNESQNScaleType","SNES_QN_SCALING_",0}; 6 const char *const SNESQNRestartTypes[] = {"DEFAULT","NONE","POWELL","PERIODIC","SNESQNRestartType","SNES_QN_RESTART_",0}; 7 const char *const SNESQNTypes[] = {"LBFGS","BROYDEN","BADBROYDEN","SNESQNType","SNES_QN_",0}; 8 9 typedef struct { 10 Vec *U; /* Stored past states (vary from method to method) */ 11 Vec *V; /* Stored past states (vary from method to method) */ 12 PetscInt m; /* The number of kept previous steps */ 13 PetscReal *lambda; /* The line search history of the method */ 14 PetscReal *norm; /* norms of the steps */ 15 PetscScalar *alpha, *beta; 16 PetscScalar *dXtdF, *dFtdX, *YtdX; 17 PetscBool singlereduction; /* Aggregated reduction implementation */ 18 PetscScalar *dXdFmat; /* A matrix of values for dX_i dot dF_j */ 19 PetscViewer monitor; 20 PetscReal powell_gamma; /* Powell angle restart condition */ 21 PetscReal powell_downhill; /* Powell descent restart condition */ 22 PetscReal scaling; /* scaling of H0 */ 23 SNESQNType type; /* the type of quasi-newton method used */ 24 SNESQNScaleType scale_type; /* the type of scaling used */ 25 SNESQNRestartType restart_type; /* determine the frequency and type of restart conditions */ 26 } SNES_QN; 27 28 #undef __FUNCT__ 29 #define __FUNCT__ "SNESQNApply_Broyden" 30 PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D) 31 { 32 PetscErrorCode ierr; 33 SNES_QN *qn = (SNES_QN*)snes->data; 34 Vec W = snes->work[3]; 35 Vec *U = qn->U; 36 KSPConvergedReason kspreason; 37 PetscInt m = qn->m; 38 PetscInt k,i,j,lits,l = m; 39 PetscReal unorm,a,b; 40 PetscReal *lambda=qn->lambda; 41 PetscScalar gdot; 42 PetscReal udot; 43 44 PetscFunctionBegin; 45 if (it < m) l = it; 46 if (it > 0) { 47 k = (it-1)%l; 48 ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr); 49 ierr = VecCopy(Xold,U[k]);CHKERRQ(ierr); 50 ierr = VecAXPY(U[k],-1.0,X);CHKERRQ(ierr); 51 if (qn->monitor) { 52 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 53 ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr); 54 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 55 } 56 } 57 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 58 ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr); 59 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 60 if (kspreason < 0) { 61 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 62 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 63 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 64 PetscFunctionReturn(0); 65 } 66 } 67 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 68 snes->linear_its += lits; 69 ierr = VecCopy(W,Y);CHKERRQ(ierr); 70 } else { 71 ierr = VecCopy(D,Y);CHKERRQ(ierr); 72 ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr); 73 } 74 75 /* inward recursion starting at the first update and working forward */ 76 for (i = 0; i < l-1; i++) { 77 j = (it+i-l)%l; 78 k = (it+i-l+1)%l; 79 ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr); 80 ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr); 81 unorm *= unorm; 82 udot = PetscRealPart(gdot); 83 a = (lambda[j]/lambda[k]); 84 b = -(1.-lambda[j]); 85 a *= udot/unorm; 86 b *= udot/unorm; 87 ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr); 88 89 if (qn->monitor) { 90 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 91 ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,PetscRealPart(gdot));CHKERRQ(ierr); 92 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 93 } 94 } 95 if (l > 0) { 96 k = (it-1)%l; 97 ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr); 98 ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr); 99 unorm *= unorm; 100 udot = PetscRealPart(gdot); 101 a = unorm/(unorm-lambda[k]*udot); 102 b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot); 103 if (qn->monitor) { 104 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 105 ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: a: %14.12e b: %14.12e \n",k,a,b);CHKERRQ(ierr); 106 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 107 } 108 ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr); 109 } 110 l = m; 111 if (it+1<m)l=it+1; 112 k = it%l; 113 if (qn->monitor) { 114 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 115 ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr); 116 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 117 } 118 PetscFunctionReturn(0); 119 } 120 121 #undef __FUNCT__ 122 #define __FUNCT__ "SNESQNApply_BadBroyden" 123 PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold) 124 { 125 PetscErrorCode ierr; 126 SNES_QN *qn = (SNES_QN*)snes->data; 127 Vec W = snes->work[3]; 128 Vec *U = qn->U; 129 Vec *T = qn->V; 130 131 /* ksp thing for jacobian scaling */ 132 KSPConvergedReason kspreason; 133 PetscInt h,k,j,i,lits; 134 PetscInt m = qn->m; 135 PetscScalar gdot,udot; 136 PetscInt l = m; 137 138 PetscFunctionBegin; 139 if (it < m) l = it; 140 ierr = VecCopy(D,Y);CHKERRQ(ierr); 141 if (l > 0) { 142 k = (it-1)%l; 143 ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->lambda[k]);CHKERRQ(ierr); 144 ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr); 145 ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr); 146 ierr = VecCopy(Xold,T[k]);CHKERRQ(ierr); 147 ierr = VecAXPY(T[k],-1.0,X);CHKERRQ(ierr); 148 } 149 150 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 151 ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr); 152 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 153 if (kspreason < 0) { 154 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 155 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 156 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 157 PetscFunctionReturn(0); 158 } 159 } 160 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 161 snes->linear_its += lits; 162 ierr = VecCopy(W,Y);CHKERRQ(ierr); 163 } else { 164 ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr); 165 } 166 167 /* inward recursion starting at the first update and working forward */ 168 if (l > 0) { 169 for (i = 0; i < l-1; i++) { 170 j = (it+i-l)%l; 171 k = (it+i-l+1)%l; 172 h = (it-1)%l; 173 ierr = VecDotBegin(U[j],U[h],&gdot);CHKERRQ(ierr); 174 ierr = VecDotBegin(U[j],U[j],&udot);CHKERRQ(ierr); 175 ierr = VecDotEnd(U[j],U[h],&gdot);CHKERRQ(ierr); 176 ierr = VecDotEnd(U[j],U[j],&udot);CHKERRQ(ierr); 177 ierr = VecAXPY(Y,PetscRealPart(gdot)/PetscRealPart(udot),T[k]);CHKERRQ(ierr); 178 ierr = VecAXPY(Y,-(1.-qn->lambda[k])*PetscRealPart(gdot)/PetscRealPart(udot),T[j]);CHKERRQ(ierr); 179 if (qn->monitor) { 180 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 181 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr); 182 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 183 } 184 } 185 } 186 PetscFunctionReturn(0); 187 } 188 189 #undef __FUNCT__ 190 #define __FUNCT__ "SNESQNApply_LBFGS" 191 PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold) 192 { 193 PetscErrorCode ierr; 194 SNES_QN *qn = (SNES_QN*)snes->data; 195 Vec W = snes->work[3]; 196 Vec *dX = qn->U; 197 Vec *dF = qn->V; 198 PetscScalar *alpha = qn->alpha; 199 PetscScalar *beta = qn->beta; 200 PetscScalar *dXtdF = qn->dXtdF; 201 PetscScalar *dFtdX = qn->dFtdX; 202 PetscScalar *YtdX = qn->YtdX; 203 204 /* ksp thing for jacobian scaling */ 205 KSPConvergedReason kspreason; 206 PetscInt k,i,j,g,lits; 207 PetscInt m = qn->m; 208 PetscScalar t; 209 PetscInt l = m; 210 211 PetscFunctionBegin; 212 if (it < m) l = it; 213 ierr = VecCopy(D,Y);CHKERRQ(ierr); 214 if (it > 0) { 215 k = (it - 1) % l; 216 ierr = VecCopy(D,dF[k]);CHKERRQ(ierr); 217 ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr); 218 ierr = VecCopy(X, dX[k]);CHKERRQ(ierr); 219 ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr); 220 if (qn->singlereduction) { 221 ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr); 222 ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr); 223 ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr); 224 ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr); 225 ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr); 226 ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr); 227 for (j = 0; j < l; j++) { 228 H(k, j) = dFtdX[j]; 229 H(j, k) = dXtdF[j]; 230 } 231 /* copy back over to make the computation of alpha and beta easier */ 232 for (j = 0; j < l; j++) dXtdF[j] = H(j, j); 233 } else { 234 ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr); 235 } 236 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 237 ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr); 238 } 239 } 240 241 /* outward recursion starting at iteration k's update and working back */ 242 for (i=0; i<l; i++) { 243 k = (it-i-1)%l; 244 if (qn->singlereduction) { 245 /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */ 246 t = YtdX[k]; 247 for (j=0; j<i; j++) { 248 g = (it-j-1)%l; 249 t -= alpha[g]*H(k, g); 250 } 251 alpha[k] = t/H(k,k); 252 } else { 253 ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr); 254 alpha[k] = t/dXtdF[k]; 255 } 256 if (qn->monitor) { 257 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 258 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); 259 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 260 } 261 ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr); 262 } 263 264 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 265 ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr); 266 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 267 if (kspreason < 0) { 268 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 269 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 270 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 271 PetscFunctionReturn(0); 272 } 273 } 274 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 275 snes->linear_its += lits; 276 ierr = VecCopy(W, Y);CHKERRQ(ierr); 277 } else { 278 ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); 279 } 280 if (qn->singlereduction) { 281 ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr); 282 } 283 /* inward recursion starting at the first update and working forward */ 284 for (i = 0; i < l; i++) { 285 k = (it + i - l) % l; 286 if (qn->singlereduction) { 287 t = YtdX[k]; 288 for (j = 0; j < i; j++) { 289 g = (it + j - l) % l; 290 t += (alpha[g] - beta[g])*H(g, k); 291 } 292 beta[k] = t / H(k, k); 293 } else { 294 ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); 295 beta[k] = t / dXtdF[k]; 296 } 297 ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr); 298 if (qn->monitor) { 299 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 300 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); 301 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 302 } 303 } 304 PetscFunctionReturn(0); 305 } 306 307 #undef __FUNCT__ 308 #define __FUNCT__ "SNESSolve_QN" 309 static PetscErrorCode SNESSolve_QN(SNES snes) 310 { 311 PetscErrorCode ierr; 312 SNES_QN *qn = (SNES_QN*) snes->data; 313 Vec X,Xold; 314 Vec F,W; 315 Vec Y,D,Dold; 316 PetscInt i, i_r; 317 PetscReal fnorm,xnorm,ynorm,gnorm; 318 PetscBool lssucceed,powell,periodic; 319 PetscScalar DolddotD,DolddotDold; 320 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 321 SNESConvergedReason reason; 322 323 /* basically just a regular newton's method except for the application of the jacobian */ 324 325 PetscFunctionBegin; 326 ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); 327 F = snes->vec_func; /* residual vector */ 328 Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 329 W = snes->work[3]; 330 X = snes->vec_sol; /* solution vector */ 331 Xold = snes->work[0]; 332 333 /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ 334 D = snes->work[1]; 335 Dold = snes->work[2]; 336 337 snes->reason = SNES_CONVERGED_ITERATING; 338 339 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 340 snes->iter = 0; 341 snes->norm = 0.; 342 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 343 344 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { 345 ierr = SNESApplyPC(snes,X,NULL,F);CHKERRQ(ierr); 346 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 347 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 348 snes->reason = SNES_DIVERGED_INNER; 349 PetscFunctionReturn(0); 350 } 351 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 352 } else { 353 if (!snes->vec_func_init_set) { 354 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 355 if (snes->domainerror) { 356 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 357 PetscFunctionReturn(0); 358 } 359 } else snes->vec_func_init_set = PETSC_FALSE; 360 361 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 362 if (PetscIsInfOrNanReal(fnorm)) { 363 snes->reason = SNES_DIVERGED_FNORM_NAN; 364 PetscFunctionReturn(0); 365 } 366 } 367 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 368 ierr = SNESApplyPC(snes,X,F,D);CHKERRQ(ierr); 369 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 370 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 371 snes->reason = SNES_DIVERGED_INNER; 372 PetscFunctionReturn(0); 373 } 374 } else { 375 ierr = VecCopy(F,D);CHKERRQ(ierr); 376 } 377 378 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 379 snes->norm = fnorm; 380 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 381 ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); 382 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 383 384 /* test convergence */ 385 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 386 if (snes->reason) PetscFunctionReturn(0); 387 388 if (snes->pc && snes->pcside == PC_RIGHT) { 389 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 390 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 391 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 392 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 393 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 394 snes->reason = SNES_DIVERGED_INNER; 395 PetscFunctionReturn(0); 396 } 397 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 398 ierr = VecCopy(F,D);CHKERRQ(ierr); 399 } 400 401 /* scale the initial update */ 402 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 403 ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre,&flg);CHKERRQ(ierr); 404 if (flg == SAME_PRECONDITIONER) {ierr = KSPSetReusePreconditioner(snes->ksp,PETSC_TRUE);CHKERRQ(ierr);} 405 else {ierr = KSPSetReusePreconditioner(snes->ksp,PETSC_FALSE);CHKERRQ(ierr);} 406 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); 407 } 408 409 for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 410 if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) { 411 PetscScalar ff,xf; 412 ierr = VecCopy(Dold,Y);CHKERRQ(ierr); 413 ierr = VecCopy(Xold,W);CHKERRQ(ierr); 414 ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr); 415 ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr); 416 ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr); 417 ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr); 418 ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr); 419 ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr); 420 qn->scaling = PetscRealPart(xf)/PetscRealPart(ff); 421 } 422 switch (qn->type) { 423 case SNES_QN_BADBROYDEN: 424 ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 425 break; 426 case SNES_QN_BROYDEN: 427 ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr); 428 break; 429 case SNES_QN_LBFGS: 430 SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 431 break; 432 } 433 /* line search for lambda */ 434 ynorm = 1; gnorm = fnorm; 435 ierr = VecCopy(D, Dold);CHKERRQ(ierr); 436 ierr = VecCopy(X, Xold);CHKERRQ(ierr); 437 ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); 438 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 439 if (snes->domainerror) { 440 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 441 PetscFunctionReturn(0); 442 } 443 ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 444 if (!lssucceed) { 445 if (++snes->numFailures >= snes->maxFailures) { 446 snes->reason = SNES_DIVERGED_LINE_SEARCH; 447 break; 448 } 449 } 450 ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); 451 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 452 ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); 453 } 454 455 /* convergence monitoring */ 456 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); 457 458 if (snes->pc && snes->pcside == PC_RIGHT) { 459 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 460 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 461 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 462 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 463 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 464 snes->reason = SNES_DIVERGED_INNER; 465 PetscFunctionReturn(0); 466 } 467 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 468 } 469 470 ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 471 ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); 472 473 ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 474 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 475 /* set parameter for default relative tolerance convergence test */ 476 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 477 if (snes->reason) PetscFunctionReturn(0); 478 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 479 ierr = SNESApplyPC(snes,X,F,D);CHKERRQ(ierr); 480 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 481 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 482 snes->reason = SNES_DIVERGED_INNER; 483 PetscFunctionReturn(0); 484 } 485 } else { 486 ierr = VecCopy(F, D);CHKERRQ(ierr); 487 } 488 powell = PETSC_FALSE; 489 if (qn->restart_type == SNES_QN_RESTART_POWELL) { 490 /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 491 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 492 ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr); 493 } else { 494 ierr = VecCopy(Dold,W);CHKERRQ(ierr); 495 } 496 ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr); 497 ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr); 498 ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr); 499 ierr = VecDotEnd(W, D, &DolddotD);CHKERRQ(ierr); 500 if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE; 501 } 502 periodic = PETSC_FALSE; 503 if (qn->restart_type == SNES_QN_RESTART_PERIODIC) { 504 if (i_r>qn->m-1) periodic = PETSC_TRUE; 505 } 506 /* restart if either powell or periodic restart is satisfied. */ 507 if (powell || periodic) { 508 if (qn->monitor) { 509 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 510 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); 511 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 512 } 513 i_r = -1; 514 /* general purpose update */ 515 if (snes->ops->update) { 516 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 517 } 518 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 519 ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre,&flg);CHKERRQ(ierr); 520 if (flg == SAME_PRECONDITIONER) {ierr = KSPSetReusePreconditioner(snes->ksp,PETSC_TRUE);CHKERRQ(ierr);} 521 else {ierr = KSPSetReusePreconditioner(snes->ksp,PETSC_FALSE);CHKERRQ(ierr);} 522 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); 523 } 524 } 525 /* general purpose update */ 526 if (snes->ops->update) { 527 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 528 } 529 } 530 if (i == snes->max_its) { 531 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 532 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 533 } 534 PetscFunctionReturn(0); 535 } 536 537 #undef __FUNCT__ 538 #define __FUNCT__ "SNESSetUp_QN" 539 static PetscErrorCode SNESSetUp_QN(SNES snes) 540 { 541 SNES_QN *qn = (SNES_QN*)snes->data; 542 PetscErrorCode ierr; 543 544 PetscFunctionBegin; 545 ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr); 546 if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr); 547 ierr = PetscMalloc4(qn->m,&qn->alpha,qn->m,&qn->beta,qn->m,&qn->dXtdF,qn->m,&qn->lambda);CHKERRQ(ierr); 548 549 if (qn->singlereduction) { 550 ierr = PetscMalloc3(qn->m*qn->m,&qn->dXdFmat,qn->m,&qn->dFtdX,qn->m,&qn->YtdX);CHKERRQ(ierr); 551 } 552 ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr); 553 /* set method defaults */ 554 if (qn->scale_type == SNES_QN_SCALE_DEFAULT) { 555 if (qn->type == SNES_QN_BADBROYDEN) { 556 qn->scale_type = SNES_QN_SCALE_NONE; 557 } else { 558 qn->scale_type = SNES_QN_SCALE_SHANNO; 559 } 560 } 561 if (qn->restart_type == SNES_QN_RESTART_DEFAULT) { 562 if (qn->type == SNES_QN_LBFGS) { 563 qn->restart_type = SNES_QN_RESTART_POWELL; 564 } else { 565 qn->restart_type = SNES_QN_RESTART_PERIODIC; 566 } 567 } 568 569 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 570 ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); 571 } 572 if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;} 573 PetscFunctionReturn(0); 574 } 575 576 #undef __FUNCT__ 577 #define __FUNCT__ "SNESReset_QN" 578 static PetscErrorCode SNESReset_QN(SNES snes) 579 { 580 PetscErrorCode ierr; 581 SNES_QN *qn; 582 583 PetscFunctionBegin; 584 if (snes->data) { 585 qn = (SNES_QN*)snes->data; 586 if (qn->U) { 587 ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr); 588 } 589 if (qn->V) { 590 ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr); 591 } 592 if (qn->singlereduction) { 593 ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr); 594 } 595 ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr); 596 } 597 PetscFunctionReturn(0); 598 } 599 600 #undef __FUNCT__ 601 #define __FUNCT__ "SNESDestroy_QN" 602 static PetscErrorCode SNESDestroy_QN(SNES snes) 603 { 604 PetscErrorCode ierr; 605 606 PetscFunctionBegin; 607 ierr = SNESReset_QN(snes);CHKERRQ(ierr); 608 ierr = PetscFree(snes->data);CHKERRQ(ierr); 609 ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr); 610 PetscFunctionReturn(0); 611 } 612 613 #undef __FUNCT__ 614 #define __FUNCT__ "SNESSetFromOptions_QN" 615 static PetscErrorCode SNESSetFromOptions_QN(SNES snes) 616 { 617 618 PetscErrorCode ierr; 619 SNES_QN *qn = (SNES_QN*)snes->data; 620 PetscBool monflg = PETSC_FALSE,flg; 621 SNESLineSearch linesearch; 622 SNESQNRestartType rtype = qn->restart_type; 623 SNESQNScaleType stype = qn->scale_type; 624 SNESQNType qtype = qn->type; 625 626 PetscFunctionBegin; 627 ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr); 628 ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr); 629 ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr); 630 ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance", "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr); 631 ierr = PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr); 632 ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions", "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr); 633 ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr); 634 if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr); 635 636 ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr); 637 if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr); 638 639 ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes, 640 (PetscEnum)qtype,(PetscEnum*)&qtype,&flg);CHKERRQ(ierr); 641 if (flg) {ierr = SNESQNSetType(snes,qtype);CHKERRQ(ierr);} 642 ierr = PetscOptionsTail();CHKERRQ(ierr); 643 if (!snes->linesearch) { 644 ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); 645 if (qn->type == SNES_QN_LBFGS) { 646 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr); 647 } else if (qn->type == SNES_QN_BROYDEN) { 648 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr); 649 } else { 650 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr); 651 } 652 } 653 if (monflg) { 654 qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr); 655 } 656 PetscFunctionReturn(0); 657 } 658 659 #undef __FUNCT__ 660 #define __FUNCT__ "SNESView_QN" 661 static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer) 662 { 663 SNES_QN *qn = (SNES_QN*)snes->data; 664 PetscBool iascii; 665 PetscErrorCode ierr; 666 667 PetscFunctionBegin; 668 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 669 if (iascii) { 670 ierr = PetscViewerASCIIPrintf(viewer," QN type is %s, restart type is %s, scale type is %s\n",SNESQNTypes[qn->type],SNESQNRestartTypes[qn->restart_type],SNESQNScaleTypes[qn->scale_type]);CHKERRQ(ierr); 671 ierr = PetscViewerASCIIPrintf(viewer," Stored subspace size: %d\n", qn->m);CHKERRQ(ierr); 672 if (qn->singlereduction) { 673 ierr = PetscViewerASCIIPrintf(viewer," Using the single reduction variant.\n");CHKERRQ(ierr); 674 } 675 } 676 PetscFunctionReturn(0); 677 } 678 679 #undef __FUNCT__ 680 #define __FUNCT__ "SNESQNSetRestartType" 681 /*@ 682 SNESQNSetRestartType - Sets the restart type for SNESQN. 683 684 Logically Collective on SNES 685 686 Input Parameters: 687 + snes - the iterative context 688 - rtype - restart type 689 690 Options Database: 691 + -snes_qn_restart_type<powell,periodic,none> - set the restart type 692 - -snes_qn_restart[10] - sets the number of iterations before restart for periodic 693 694 Level: intermediate 695 696 SNESQNRestartTypes: 697 + SNES_QN_RESTART_NONE - never restart 698 . SNES_QN_RESTART_POWELL - restart based upon descent criteria 699 - SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations 700 701 Notes: 702 The default line search used is the L2 line search and it requires two additional function evaluations. 703 704 .keywords: SNES, SNESQN, restart, type, set SNESLineSearch 705 @*/ 706 PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype) 707 { 708 PetscErrorCode ierr; 709 710 PetscFunctionBegin; 711 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 712 ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr); 713 PetscFunctionReturn(0); 714 } 715 716 #undef __FUNCT__ 717 #define __FUNCT__ "SNESQNSetScaleType" 718 /*@ 719 SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN. 720 721 Logically Collective on SNES 722 723 Input Parameters: 724 + snes - the iterative context 725 - stype - scale type 726 727 Options Database: 728 . -snes_qn_scale_type<shanno,none,linesearch,jacobian> 729 730 Level: intermediate 731 732 SNESQNSelectTypes: 733 + SNES_QN_SCALE_NONE - don't scale the problem 734 . SNES_QN_SCALE_SHANNO - use shanno scaling 735 . SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda 736 - SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian. 737 738 .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch 739 @*/ 740 741 PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype) 742 { 743 PetscErrorCode ierr; 744 745 PetscFunctionBegin; 746 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 747 ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr); 748 PetscFunctionReturn(0); 749 } 750 751 #undef __FUNCT__ 752 #define __FUNCT__ "SNESQNSetScaleType_QN" 753 PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype) 754 { 755 SNES_QN *qn = (SNES_QN*)snes->data; 756 757 PetscFunctionBegin; 758 qn->scale_type = stype; 759 PetscFunctionReturn(0); 760 } 761 762 #undef __FUNCT__ 763 #define __FUNCT__ "SNESQNSetRestartType_QN" 764 PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype) 765 { 766 SNES_QN *qn = (SNES_QN*)snes->data; 767 768 PetscFunctionBegin; 769 qn->restart_type = rtype; 770 PetscFunctionReturn(0); 771 } 772 773 #undef __FUNCT__ 774 #define __FUNCT__ "SNESQNSetType" 775 /*@ 776 SNESQNSetType - Sets the quasi-Newton variant to be used in SNESQN. 777 778 Logically Collective on SNES 779 780 Input Parameters: 781 + snes - the iterative context 782 - qtype - variant type 783 784 Options Database: 785 . -snes_qn_scale_type<lbfgs,broyden,badbroyden> 786 787 Level: beginner 788 789 SNESQNTypes: 790 + SNES_QN_LBFGS - LBFGS variant 791 . SNES_QN_BROYDEN - Broyden variant 792 - SNES_QN_BADBROYDEN - Bad Broyden variant 793 794 .keywords: SNES, SNESQN, type, set 795 @*/ 796 797 PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype) 798 { 799 PetscErrorCode ierr; 800 801 PetscFunctionBegin; 802 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 803 ierr = PetscTryMethod(snes,"SNESQNSetType_C",(SNES,SNESQNType),(snes,qtype));CHKERRQ(ierr); 804 PetscFunctionReturn(0); 805 } 806 807 #undef __FUNCT__ 808 #define __FUNCT__ "SNESQNSetType_QN" 809 PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype) 810 { 811 SNES_QN *qn = (SNES_QN*)snes->data; 812 813 PetscFunctionBegin; 814 qn->type = qtype; 815 PetscFunctionReturn(0); 816 } 817 818 /* -------------------------------------------------------------------------- */ 819 /*MC 820 SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems. 821 822 Options Database: 823 824 + -snes_qn_m - Number of past states saved for the L-Broyden methods. 825 . -snes_qn_powell_angle - Angle condition for restart. 826 . -snes_qn_powell_descent - Descent condition for restart. 827 . -snes_linesearch_type <cp, l2, basic> - Type of line search. 828 - -snes_qn_monitor - Monitors the quasi-newton jacobian. 829 830 Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using 831 previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one 832 updates. 833 834 When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied. The first of 835 these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this 836 iteration as the current iteration's values when constructing the approximate jacobian. The second, composed, 837 perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner. 838 839 References: 840 841 Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995. 842 843 R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi-Newton Matrices and their use in Limited Memory Methods, 844 Technical Report, Northwestern University, June 1992. 845 846 Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE 847 Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985. 848 849 850 Level: beginner 851 852 .seealso: SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR 853 854 M*/ 855 #undef __FUNCT__ 856 #define __FUNCT__ "SNESCreate_QN" 857 PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes) 858 { 859 PetscErrorCode ierr; 860 SNES_QN *qn; 861 862 PetscFunctionBegin; 863 snes->ops->setup = SNESSetUp_QN; 864 snes->ops->solve = SNESSolve_QN; 865 snes->ops->destroy = SNESDestroy_QN; 866 snes->ops->setfromoptions = SNESSetFromOptions_QN; 867 snes->ops->view = SNESView_QN; 868 snes->ops->reset = SNESReset_QN; 869 870 snes->pcside = PC_LEFT; 871 872 snes->usespc = PETSC_TRUE; 873 snes->usesksp = PETSC_FALSE; 874 875 if (!snes->tolerancesset) { 876 snes->max_funcs = 30000; 877 snes->max_its = 10000; 878 } 879 880 ierr = PetscNewLog(snes,&qn);CHKERRQ(ierr); 881 snes->data = (void*) qn; 882 qn->m = 10; 883 qn->scaling = 1.0; 884 qn->U = NULL; 885 qn->V = NULL; 886 qn->dXtdF = NULL; 887 qn->dFtdX = NULL; 888 qn->dXdFmat = NULL; 889 qn->monitor = NULL; 890 qn->singlereduction = PETSC_TRUE; 891 qn->powell_gamma = 0.9999; 892 qn->scale_type = SNES_QN_SCALE_DEFAULT; 893 qn->restart_type = SNES_QN_RESTART_DEFAULT; 894 qn->type = SNES_QN_LBFGS; 895 896 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr); 897 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr); 898 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetType_C",SNESQNSetType_QN);CHKERRQ(ierr); 899 PetscFunctionReturn(0); 900 } 901