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