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 F = snes->vec_func; /* residual vector */ 327 Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 328 W = snes->work[3]; 329 X = snes->vec_sol; /* solution vector */ 330 Xold = snes->work[0]; 331 332 /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ 333 D = snes->work[1]; 334 Dold = snes->work[2]; 335 336 snes->reason = SNES_CONVERGED_ITERATING; 337 338 ierr = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr); 339 snes->iter = 0; 340 snes->norm = 0.; 341 ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr); 342 343 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { 344 ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr); 345 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 346 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 347 snes->reason = SNES_DIVERGED_INNER; 348 PetscFunctionReturn(0); 349 } 350 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 351 } else { 352 if (!snes->vec_func_init_set) { 353 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 354 if (snes->domainerror) { 355 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 356 PetscFunctionReturn(0); 357 } 358 } else snes->vec_func_init_set = PETSC_FALSE; 359 360 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 361 if (PetscIsInfOrNanReal(fnorm)) { 362 snes->reason = SNES_DIVERGED_FNORM_NAN; 363 PetscFunctionReturn(0); 364 } 365 } 366 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 367 ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr); 368 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 369 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 370 snes->reason = SNES_DIVERGED_INNER; 371 PetscFunctionReturn(0); 372 } 373 } else { 374 ierr = VecCopy(F,D);CHKERRQ(ierr); 375 } 376 377 ierr = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr); 378 snes->norm = fnorm; 379 ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr); 380 ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); 381 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 382 383 /* test convergence */ 384 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 385 if (snes->reason) PetscFunctionReturn(0); 386 387 if (snes->pc && snes->pcside == PC_RIGHT) { 388 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 389 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 390 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 391 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 392 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 393 snes->reason = SNES_DIVERGED_INNER; 394 PetscFunctionReturn(0); 395 } 396 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 397 ierr = VecCopy(F,D);CHKERRQ(ierr); 398 } 399 400 /* scale the initial update */ 401 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 402 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 403 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 404 } 405 406 for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 407 if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) { 408 PetscScalar ff,xf; 409 ierr = VecCopy(Dold,Y);CHKERRQ(ierr); 410 ierr = VecCopy(Xold,W);CHKERRQ(ierr); 411 ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr); 412 ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr); 413 ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr); 414 ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr); 415 ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr); 416 ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr); 417 qn->scaling = PetscRealPart(xf)/PetscRealPart(ff); 418 } 419 switch (qn->type) { 420 case SNES_QN_BADBROYDEN: 421 ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 422 break; 423 case SNES_QN_BROYDEN: 424 ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr); 425 break; 426 case SNES_QN_LBFGS: 427 SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 428 break; 429 } 430 /* line search for lambda */ 431 ynorm = 1; gnorm = fnorm; 432 ierr = VecCopy(D, Dold);CHKERRQ(ierr); 433 ierr = VecCopy(X, Xold);CHKERRQ(ierr); 434 ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); 435 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 436 if (snes->domainerror) { 437 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 438 PetscFunctionReturn(0); 439 } 440 ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 441 if (!lssucceed) { 442 if (++snes->numFailures >= snes->maxFailures) { 443 snes->reason = SNES_DIVERGED_LINE_SEARCH; 444 break; 445 } 446 } 447 ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); 448 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 449 ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); 450 } 451 452 /* convergence monitoring */ 453 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); 454 455 if (snes->pc && snes->pcside == PC_RIGHT) { 456 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 457 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 458 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 459 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 460 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 461 snes->reason = SNES_DIVERGED_INNER; 462 PetscFunctionReturn(0); 463 } 464 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 465 } 466 467 ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 468 ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); 469 470 ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 471 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 472 /* set parameter for default relative tolerance convergence test */ 473 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 474 if (snes->reason) PetscFunctionReturn(0); 475 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 476 ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr); 477 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 478 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 479 snes->reason = SNES_DIVERGED_INNER; 480 PetscFunctionReturn(0); 481 } 482 } else { 483 ierr = VecCopy(F, D);CHKERRQ(ierr); 484 } 485 powell = PETSC_FALSE; 486 if (qn->restart_type == SNES_QN_RESTART_POWELL) { 487 /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 488 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 489 ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr); 490 } else { 491 ierr = VecCopy(Dold,W);CHKERRQ(ierr); 492 } 493 ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr); 494 ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr); 495 ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr); 496 ierr = VecDotEnd(W, D, &DolddotD);CHKERRQ(ierr); 497 if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE; 498 } 499 periodic = PETSC_FALSE; 500 if (qn->restart_type == SNES_QN_RESTART_PERIODIC) { 501 if (i_r>qn->m-1) periodic = PETSC_TRUE; 502 } 503 /* restart if either powell or periodic restart is satisfied. */ 504 if (powell || periodic) { 505 if (qn->monitor) { 506 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 507 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); 508 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 509 } 510 i_r = -1; 511 /* general purpose update */ 512 if (snes->ops->update) { 513 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 514 } 515 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 516 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 517 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 518 } 519 } 520 /* general purpose update */ 521 if (snes->ops->update) { 522 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 523 } 524 } 525 if (i == snes->max_its) { 526 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 527 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 528 } 529 PetscFunctionReturn(0); 530 } 531 532 #undef __FUNCT__ 533 #define __FUNCT__ "SNESSetUp_QN" 534 static PetscErrorCode SNESSetUp_QN(SNES snes) 535 { 536 SNES_QN *qn = (SNES_QN*)snes->data; 537 PetscErrorCode ierr; 538 539 PetscFunctionBegin; 540 ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr); 541 if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr); 542 ierr = PetscMalloc4(qn->m, PetscScalar, &qn->alpha, 543 qn->m, PetscScalar, &qn->beta, 544 qn->m, PetscScalar, &qn->dXtdF, 545 qn->m, PetscReal, &qn->lambda);CHKERRQ(ierr); 546 547 if (qn->singlereduction) { 548 ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat, 549 qn->m, PetscScalar, &qn->dFtdX, 550 qn->m, PetscScalar, &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,SNES_QN,&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