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 h,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 = SNESLineSearchGetLambda(snes->linesearch,&qn->lambda[k]);CHKERRQ(ierr); 151 ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr); 152 ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr); 153 ierr = VecCopy(Xold,T[k]);CHKERRQ(ierr); 154 ierr = VecAXPY(T[k],-1.0,X);CHKERRQ(ierr); 155 } 156 157 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 158 ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr); 159 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 160 if (kspreason < 0) { 161 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 162 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 163 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 164 PetscFunctionReturn(0); 165 } 166 } 167 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 168 snes->linear_its += lits; 169 ierr = VecCopy(W,Y);CHKERRQ(ierr); 170 } else { 171 ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr); 172 } 173 174 /* inward recursion starting at the first update and working forward */ 175 if (l > 0) { 176 for (i = 0; i < l-1; i++) { 177 j = (it+i-l)%l; 178 k = (it+i-l+1)%l; 179 h = (it-1)%l; 180 ierr = VecDotBegin(U[j],U[h],&gdot);CHKERRQ(ierr); 181 ierr = VecDotBegin(U[j],U[j],&udot);CHKERRQ(ierr); 182 ierr = VecDotEnd(U[j],U[h],&gdot);CHKERRQ(ierr); 183 ierr = VecDotEnd(U[j],U[j],&udot);CHKERRQ(ierr); 184 ierr = VecAXPY(Y,PetscRealPart(gdot)/PetscRealPart(udot),T[k]);CHKERRQ(ierr); 185 ierr = VecAXPY(Y,-(1.-qn->lambda[k])*PetscRealPart(gdot)/PetscRealPart(udot),T[j]);CHKERRQ(ierr); 186 if (qn->monitor) { 187 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 188 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr); 189 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 190 } 191 } 192 } 193 PetscFunctionReturn(0); 194 } 195 196 #undef __FUNCT__ 197 #define __FUNCT__ "SNESQNApply_LBFGS" 198 PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold) 199 { 200 PetscErrorCode ierr; 201 SNES_QN *qn = (SNES_QN*)snes->data; 202 Vec W = snes->work[3]; 203 Vec *dX = qn->U; 204 Vec *dF = qn->V; 205 PetscScalar *alpha = qn->alpha; 206 PetscScalar *beta = qn->beta; 207 PetscScalar *dXtdF = qn->dXtdF; 208 PetscScalar *dFtdX = qn->dFtdX; 209 PetscScalar *YtdX = qn->YtdX; 210 211 /* ksp thing for jacobian scaling */ 212 KSPConvergedReason kspreason; 213 PetscInt k,i,j,g,lits; 214 PetscInt m = qn->m; 215 PetscScalar t; 216 PetscInt l = m; 217 218 PetscFunctionBegin; 219 if (it < m) l = it; 220 ierr = VecCopy(D,Y);CHKERRQ(ierr); 221 if (it > 0) { 222 k = (it - 1) % l; 223 ierr = VecCopy(D,dF[k]);CHKERRQ(ierr); 224 ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr); 225 ierr = VecCopy(X, dX[k]);CHKERRQ(ierr); 226 ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr); 227 if (qn->singlereduction) { 228 ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr); 229 ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr); 230 ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr); 231 ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr); 232 ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr); 233 ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr); 234 for (j = 0; j < l; j++) { 235 H(k, j) = dFtdX[j]; 236 H(j, k) = dXtdF[j]; 237 } 238 /* copy back over to make the computation of alpha and beta easier */ 239 for (j = 0; j < l; j++) dXtdF[j] = H(j, j); 240 } else { 241 ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr); 242 } 243 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 244 ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr); 245 } 246 } 247 248 /* outward recursion starting at iteration k's update and working back */ 249 for (i=0; i<l; i++) { 250 k = (it-i-1)%l; 251 if (qn->singlereduction) { 252 /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */ 253 t = YtdX[k]; 254 for (j=0; j<i; j++) { 255 g = (it-j-1)%l; 256 t -= alpha[g]*H(k, g); 257 } 258 alpha[k] = t/H(k,k); 259 } else { 260 ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr); 261 alpha[k] = t/dXtdF[k]; 262 } 263 if (qn->monitor) { 264 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 265 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); 266 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 267 } 268 ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr); 269 } 270 271 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 272 ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr); 273 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 274 if (kspreason < 0) { 275 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 276 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 277 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 278 PetscFunctionReturn(0); 279 } 280 } 281 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 282 snes->linear_its += lits; 283 ierr = VecCopy(W, Y);CHKERRQ(ierr); 284 } else { 285 ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); 286 } 287 if (qn->singlereduction) { 288 ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr); 289 } 290 /* inward recursion starting at the first update and working forward */ 291 for (i = 0; i < l; i++) { 292 k = (it + i - l) % l; 293 if (qn->singlereduction) { 294 t = YtdX[k]; 295 for (j = 0; j < i; j++) { 296 g = (it + j - l) % l; 297 t += (alpha[g] - beta[g])*H(g, k); 298 } 299 beta[k] = t / H(k, k); 300 } else { 301 ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); 302 beta[k] = t / dXtdF[k]; 303 } 304 ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr); 305 if (qn->monitor) { 306 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 307 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); 308 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 309 } 310 } 311 PetscFunctionReturn(0); 312 } 313 314 #undef __FUNCT__ 315 #define __FUNCT__ "SNESSolve_QN" 316 static PetscErrorCode SNESSolve_QN(SNES snes) 317 { 318 PetscErrorCode ierr; 319 SNES_QN *qn = (SNES_QN*) snes->data; 320 Vec X,Xold; 321 Vec F,W; 322 Vec Y,D,Dold; 323 PetscInt i, i_r; 324 PetscReal fnorm,xnorm,ynorm,gnorm; 325 PetscBool lssucceed,powell,periodic; 326 PetscScalar DolddotD,DolddotDold; 327 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 328 SNESConvergedReason reason; 329 330 /* basically just a regular newton's method except for the application of the jacobian */ 331 332 PetscFunctionBegin; 333 F = snes->vec_func; /* residual vector */ 334 Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 335 W = snes->work[3]; 336 X = snes->vec_sol; /* solution vector */ 337 Xold = snes->work[0]; 338 339 /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ 340 D = snes->work[1]; 341 Dold = snes->work[2]; 342 343 snes->reason = SNES_CONVERGED_ITERATING; 344 345 ierr = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr); 346 snes->iter = 0; 347 snes->norm = 0.; 348 ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr); 349 350 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { 351 ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr); 352 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 353 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 354 snes->reason = SNES_DIVERGED_INNER; 355 PetscFunctionReturn(0); 356 } 357 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 358 } else { 359 if (!snes->vec_func_init_set) { 360 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 361 if (snes->domainerror) { 362 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 363 PetscFunctionReturn(0); 364 } 365 } else snes->vec_func_init_set = PETSC_FALSE; 366 367 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); 368 if (PetscIsInfOrNanReal(fnorm)) { 369 snes->reason = SNES_DIVERGED_FNORM_NAN; 370 PetscFunctionReturn(0); 371 } 372 } 373 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 374 ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr); 375 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 376 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 377 snes->reason = SNES_DIVERGED_INNER; 378 PetscFunctionReturn(0); 379 } 380 } else { 381 ierr = VecCopy(F,D);CHKERRQ(ierr); 382 } 383 384 ierr = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr); 385 snes->norm = fnorm; 386 ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr); 387 ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); 388 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 389 390 /* test convergence */ 391 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 392 if (snes->reason) PetscFunctionReturn(0); 393 394 if (snes->pc && snes->pcside == PC_RIGHT) { 395 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 396 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 397 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 398 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 399 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 400 snes->reason = SNES_DIVERGED_INNER; 401 PetscFunctionReturn(0); 402 } 403 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 404 ierr = VecCopy(F,D);CHKERRQ(ierr); 405 } 406 407 /* scale the initial update */ 408 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 409 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 410 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 411 } 412 413 for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 414 if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) { 415 PetscScalar ff,xf; 416 ierr = VecCopy(Dold,Y);CHKERRQ(ierr); 417 ierr = VecCopy(Xold,W);CHKERRQ(ierr); 418 ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr); 419 ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr); 420 ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr); 421 ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr); 422 ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr); 423 ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr); 424 qn->scaling = PetscRealPart(xf)/PetscRealPart(ff); 425 } 426 switch (qn->type) { 427 case SNES_QN_BADBROYDEN: 428 ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 429 break; 430 case SNES_QN_BROYDEN: 431 ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr); 432 break; 433 case SNES_QN_LBFGS: 434 SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 435 break; 436 } 437 /* line search for lambda */ 438 ynorm = 1; gnorm = fnorm; 439 ierr = VecCopy(D, Dold);CHKERRQ(ierr); 440 ierr = VecCopy(X, Xold);CHKERRQ(ierr); 441 ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); 442 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 443 if (snes->domainerror) { 444 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 445 PetscFunctionReturn(0); 446 } 447 ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 448 if (!lssucceed) { 449 if (++snes->numFailures >= snes->maxFailures) { 450 snes->reason = SNES_DIVERGED_LINE_SEARCH; 451 break; 452 } 453 } 454 ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); 455 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 456 ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); 457 } 458 459 /* convergence monitoring */ 460 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); 461 462 if (snes->pc && snes->pcside == PC_RIGHT) { 463 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 464 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 465 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 466 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 467 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 468 snes->reason = SNES_DIVERGED_INNER; 469 PetscFunctionReturn(0); 470 } 471 ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 472 } 473 474 ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 475 ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); 476 477 ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 478 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 479 /* set parameter for default relative tolerance convergence test */ 480 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 481 if (snes->reason) PetscFunctionReturn(0); 482 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 483 ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr); 484 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 485 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 486 snes->reason = SNES_DIVERGED_INNER; 487 PetscFunctionReturn(0); 488 } 489 } else { 490 ierr = VecCopy(F, D);CHKERRQ(ierr); 491 } 492 powell = PETSC_FALSE; 493 if (qn->restart_type == SNES_QN_RESTART_POWELL) { 494 /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 495 ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr); 496 ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr); 497 ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr); 498 ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr); 499 if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE; 500 } 501 periodic = PETSC_FALSE; 502 if (qn->restart_type == SNES_QN_RESTART_PERIODIC) { 503 if (i_r>qn->m-1) periodic = PETSC_TRUE; 504 } 505 /* restart if either powell or periodic restart is satisfied. */ 506 if (powell || periodic) { 507 if (qn->monitor) { 508 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 509 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); 510 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 511 } 512 i_r = -1; 513 /* general purpose update */ 514 if (snes->ops->update) { 515 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 516 } 517 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 518 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 519 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 520 } 521 } 522 /* general purpose update */ 523 if (snes->ops->update) { 524 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 525 } 526 } 527 if (i == snes->max_its) { 528 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 529 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 530 } 531 PetscFunctionReturn(0); 532 } 533 534 #undef __FUNCT__ 535 #define __FUNCT__ "SNESSetUp_QN" 536 static PetscErrorCode SNESSetUp_QN(SNES snes) 537 { 538 SNES_QN *qn = (SNES_QN*)snes->data; 539 PetscErrorCode ierr; 540 541 PetscFunctionBegin; 542 ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr); 543 if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr); 544 ierr = PetscMalloc4(qn->m, PetscScalar, &qn->alpha, 545 qn->m, PetscScalar, &qn->beta, 546 qn->m, PetscScalar, &qn->dXtdF, 547 qn->m, PetscReal, &qn->lambda);CHKERRQ(ierr); 548 549 if (qn->singlereduction) { 550 ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat, 551 qn->m, PetscScalar, &qn->dFtdX, 552 qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr); 553 } 554 ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr); 555 /* set up the line search */ 556 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 557 ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); 558 } 559 if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;} 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