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 SNESConvergedReason reason; 321 322 /* basically just a regular newton's method except for the application of the jacobian */ 323 324 PetscFunctionBegin; 325 ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 339 snes->iter = 0; 340 snes->norm = 0.; 341 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 342 343 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { 344 ierr = SNESApplyNPC(snes,X,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 = SNESApplyNPC(snes,X,F,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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 378 snes->norm = fnorm; 379 ierr = PetscObjectSAWsGrantAccess((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 = SNESGetNPCFunction(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);CHKERRQ(ierr); 403 } 404 405 for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { 406 if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) { 407 PetscScalar ff,xf; 408 ierr = VecCopy(Dold,Y);CHKERRQ(ierr); 409 ierr = VecCopy(Xold,W);CHKERRQ(ierr); 410 ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr); 411 ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr); 412 ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr); 413 ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr); 414 ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr); 415 ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr); 416 qn->scaling = PetscRealPart(xf)/PetscRealPart(ff); 417 } 418 switch (qn->type) { 419 case SNES_QN_BADBROYDEN: 420 ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 421 break; 422 case SNES_QN_BROYDEN: 423 ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr); 424 break; 425 case SNES_QN_LBFGS: 426 SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); 427 break; 428 } 429 /* line search for lambda */ 430 ynorm = 1; gnorm = fnorm; 431 ierr = VecCopy(D, Dold);CHKERRQ(ierr); 432 ierr = VecCopy(X, Xold);CHKERRQ(ierr); 433 ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); 434 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 435 if (snes->domainerror) { 436 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 437 PetscFunctionReturn(0); 438 } 439 ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); 440 if (!lssucceed) { 441 if (++snes->numFailures >= snes->maxFailures) { 442 snes->reason = SNES_DIVERGED_LINE_SEARCH; 443 break; 444 } 445 } 446 ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); 447 if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 448 ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); 449 } 450 451 /* convergence monitoring */ 452 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); 453 454 if (snes->pc && snes->pcside == PC_RIGHT) { 455 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 456 ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); 457 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); 458 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 459 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 460 snes->reason = SNES_DIVERGED_INNER; 461 PetscFunctionReturn(0); 462 } 463 ierr = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr); 464 } 465 466 ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); 467 snes->norm = fnorm; 468 469 ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 470 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 471 /* set parameter for default relative tolerance convergence test */ 472 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 473 if (snes->reason) PetscFunctionReturn(0); 474 if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 475 ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr); 476 ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 477 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 478 snes->reason = SNES_DIVERGED_INNER; 479 PetscFunctionReturn(0); 480 } 481 } else { 482 ierr = VecCopy(F, D);CHKERRQ(ierr); 483 } 484 powell = PETSC_FALSE; 485 if (qn->restart_type == SNES_QN_RESTART_POWELL) { 486 /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ 487 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 488 ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr); 489 } else { 490 ierr = VecCopy(Dold,W);CHKERRQ(ierr); 491 } 492 ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr); 493 ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr); 494 ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr); 495 ierr = VecDotEnd(W, 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);CHKERRQ(ierr); 516 } 517 } 518 /* general purpose update */ 519 if (snes->ops->update) { 520 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 521 } 522 } 523 if (i == snes->max_its) { 524 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); 525 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 526 } 527 PetscFunctionReturn(0); 528 } 529 530 #undef __FUNCT__ 531 #define __FUNCT__ "SNESSetUp_QN" 532 static PetscErrorCode SNESSetUp_QN(SNES snes) 533 { 534 SNES_QN *qn = (SNES_QN*)snes->data; 535 PetscErrorCode ierr; 536 537 PetscFunctionBegin; 538 ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr); 539 if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr); 540 ierr = PetscMalloc4(qn->m,&qn->alpha,qn->m,&qn->beta,qn->m,&qn->dXtdF,qn->m,&qn->lambda);CHKERRQ(ierr); 541 542 if (qn->singlereduction) { 543 ierr = PetscMalloc3(qn->m*qn->m,&qn->dXdFmat,qn->m,&qn->dFtdX,qn->m,&qn->YtdX);CHKERRQ(ierr); 544 } 545 ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr); 546 /* set method defaults */ 547 if (qn->scale_type == SNES_QN_SCALE_DEFAULT) { 548 if (qn->type == SNES_QN_BADBROYDEN) { 549 qn->scale_type = SNES_QN_SCALE_NONE; 550 } else { 551 qn->scale_type = SNES_QN_SCALE_SHANNO; 552 } 553 } 554 if (qn->restart_type == SNES_QN_RESTART_DEFAULT) { 555 if (qn->type == SNES_QN_LBFGS) { 556 qn->restart_type = SNES_QN_RESTART_POWELL; 557 } else { 558 qn->restart_type = SNES_QN_RESTART_PERIODIC; 559 } 560 } 561 562 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 563 ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); 564 } 565 if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;} 566 PetscFunctionReturn(0); 567 } 568 569 #undef __FUNCT__ 570 #define __FUNCT__ "SNESReset_QN" 571 static PetscErrorCode SNESReset_QN(SNES snes) 572 { 573 PetscErrorCode ierr; 574 SNES_QN *qn; 575 576 PetscFunctionBegin; 577 if (snes->data) { 578 qn = (SNES_QN*)snes->data; 579 if (qn->U) { 580 ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr); 581 } 582 if (qn->V) { 583 ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr); 584 } 585 if (qn->singlereduction) { 586 ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr); 587 } 588 ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr); 589 } 590 PetscFunctionReturn(0); 591 } 592 593 #undef __FUNCT__ 594 #define __FUNCT__ "SNESDestroy_QN" 595 static PetscErrorCode SNESDestroy_QN(SNES snes) 596 { 597 PetscErrorCode ierr; 598 599 PetscFunctionBegin; 600 ierr = SNESReset_QN(snes);CHKERRQ(ierr); 601 ierr = PetscFree(snes->data);CHKERRQ(ierr); 602 ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr); 603 PetscFunctionReturn(0); 604 } 605 606 #undef __FUNCT__ 607 #define __FUNCT__ "SNESSetFromOptions_QN" 608 static PetscErrorCode SNESSetFromOptions_QN(SNES snes) 609 { 610 611 PetscErrorCode ierr; 612 SNES_QN *qn = (SNES_QN*)snes->data; 613 PetscBool monflg = PETSC_FALSE,flg; 614 SNESLineSearch linesearch; 615 SNESQNRestartType rtype = qn->restart_type; 616 SNESQNScaleType stype = qn->scale_type; 617 SNESQNType qtype = qn->type; 618 619 PetscFunctionBegin; 620 ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr); 621 ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr); 622 ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance", "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr); 623 ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance", "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr); 624 ierr = PetscOptionsBool("-snes_qn_monitor", "Monitor for the QN methods", "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr); 625 ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions", "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr); 626 ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr); 627 if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr); 628 629 ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr); 630 if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr); 631 632 ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes, 633 (PetscEnum)qtype,(PetscEnum*)&qtype,&flg);CHKERRQ(ierr); 634 if (flg) {ierr = SNESQNSetType(snes,qtype);CHKERRQ(ierr);} 635 ierr = PetscOptionsTail();CHKERRQ(ierr); 636 if (!snes->linesearch) { 637 ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); 638 if (qn->type == SNES_QN_LBFGS) { 639 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr); 640 } else if (qn->type == SNES_QN_BROYDEN) { 641 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr); 642 } else { 643 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr); 644 } 645 } 646 if (monflg) { 647 qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr); 648 } 649 PetscFunctionReturn(0); 650 } 651 652 #undef __FUNCT__ 653 #define __FUNCT__ "SNESView_QN" 654 static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer) 655 { 656 SNES_QN *qn = (SNES_QN*)snes->data; 657 PetscBool iascii; 658 PetscErrorCode ierr; 659 660 PetscFunctionBegin; 661 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 662 if (iascii) { 663 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); 664 ierr = PetscViewerASCIIPrintf(viewer," Stored subspace size: %d\n", qn->m);CHKERRQ(ierr); 665 if (qn->singlereduction) { 666 ierr = PetscViewerASCIIPrintf(viewer," Using the single reduction variant.\n");CHKERRQ(ierr); 667 } 668 } 669 PetscFunctionReturn(0); 670 } 671 672 #undef __FUNCT__ 673 #define __FUNCT__ "SNESQNSetRestartType" 674 /*@ 675 SNESQNSetRestartType - Sets the restart type for SNESQN. 676 677 Logically Collective on SNES 678 679 Input Parameters: 680 + snes - the iterative context 681 - rtype - restart type 682 683 Options Database: 684 + -snes_qn_restart_type<powell,periodic,none> - set the restart type 685 - -snes_qn_m - sets the number of stored updates and the restart period for periodic 686 687 Level: intermediate 688 689 SNESQNRestartTypes: 690 + SNES_QN_RESTART_NONE - never restart 691 . SNES_QN_RESTART_POWELL - restart based upon descent criteria 692 - SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations 693 694 .keywords: SNES, SNESQN, restart, type, set SNESLineSearch 695 @*/ 696 PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype) 697 { 698 PetscErrorCode ierr; 699 700 PetscFunctionBegin; 701 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 702 ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr); 703 PetscFunctionReturn(0); 704 } 705 706 #undef __FUNCT__ 707 #define __FUNCT__ "SNESQNSetScaleType" 708 /*@ 709 SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN. 710 711 Logically Collective on SNES 712 713 Input Parameters: 714 + snes - the iterative context 715 - stype - scale type 716 717 Options Database: 718 . -snes_qn_scale_type<shanno,none,linesearch,jacobian> 719 720 Level: intermediate 721 722 SNESQNSelectTypes: 723 + SNES_QN_SCALE_NONE - don't scale the problem 724 . SNES_QN_SCALE_SHANNO - use shanno scaling 725 . SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda 726 - SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian. 727 728 .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch 729 @*/ 730 731 PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype) 732 { 733 PetscErrorCode ierr; 734 735 PetscFunctionBegin; 736 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 737 ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr); 738 PetscFunctionReturn(0); 739 } 740 741 #undef __FUNCT__ 742 #define __FUNCT__ "SNESQNSetScaleType_QN" 743 PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype) 744 { 745 SNES_QN *qn = (SNES_QN*)snes->data; 746 747 PetscFunctionBegin; 748 qn->scale_type = stype; 749 PetscFunctionReturn(0); 750 } 751 752 #undef __FUNCT__ 753 #define __FUNCT__ "SNESQNSetRestartType_QN" 754 PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype) 755 { 756 SNES_QN *qn = (SNES_QN*)snes->data; 757 758 PetscFunctionBegin; 759 qn->restart_type = rtype; 760 PetscFunctionReturn(0); 761 } 762 763 #undef __FUNCT__ 764 #define __FUNCT__ "SNESQNSetType" 765 /*@ 766 SNESQNSetType - Sets the quasi-Newton variant to be used in SNESQN. 767 768 Logically Collective on SNES 769 770 Input Parameters: 771 + snes - the iterative context 772 - qtype - variant type 773 774 Options Database: 775 . -snes_qn_scale_type<lbfgs,broyden,badbroyden> 776 777 Level: beginner 778 779 SNESQNTypes: 780 + SNES_QN_LBFGS - LBFGS variant 781 . SNES_QN_BROYDEN - Broyden variant 782 - SNES_QN_BADBROYDEN - Bad Broyden variant 783 784 .keywords: SNES, SNESQN, type, set 785 @*/ 786 787 PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype) 788 { 789 PetscErrorCode ierr; 790 791 PetscFunctionBegin; 792 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 793 ierr = PetscTryMethod(snes,"SNESQNSetType_C",(SNES,SNESQNType),(snes,qtype));CHKERRQ(ierr); 794 PetscFunctionReturn(0); 795 } 796 797 #undef __FUNCT__ 798 #define __FUNCT__ "SNESQNSetType_QN" 799 PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype) 800 { 801 SNES_QN *qn = (SNES_QN*)snes->data; 802 803 PetscFunctionBegin; 804 qn->type = qtype; 805 PetscFunctionReturn(0); 806 } 807 808 /* -------------------------------------------------------------------------- */ 809 /*MC 810 SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems. 811 812 Options Database: 813 814 + -snes_qn_m - Number of past states saved for the L-Broyden methods. 815 . -snes_qn_powell_angle - Angle condition for restart. 816 . -snes_qn_powell_descent - Descent condition for restart. 817 . -snes_linesearch_type <cp, l2, basic> - Type of line search. 818 - -snes_qn_monitor - Monitors the quasi-newton jacobian. 819 820 Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using 821 previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one 822 updates. 823 824 When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied. The first of 825 these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this 826 iteration as the current iteration's values when constructing the approximate jacobian. The second, composed, 827 perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner. 828 829 References: 830 831 Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995. 832 833 R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi-Newton Matrices and their use in Limited Memory Methods, 834 Technical Report, Northwestern University, June 1992. 835 836 Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE 837 Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985. 838 839 840 Level: beginner 841 842 .seealso: SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR 843 844 M*/ 845 #undef __FUNCT__ 846 #define __FUNCT__ "SNESCreate_QN" 847 PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes) 848 { 849 PetscErrorCode ierr; 850 SNES_QN *qn; 851 852 PetscFunctionBegin; 853 snes->ops->setup = SNESSetUp_QN; 854 snes->ops->solve = SNESSolve_QN; 855 snes->ops->destroy = SNESDestroy_QN; 856 snes->ops->setfromoptions = SNESSetFromOptions_QN; 857 snes->ops->view = SNESView_QN; 858 snes->ops->reset = SNESReset_QN; 859 860 snes->pcside = PC_LEFT; 861 862 snes->usespc = PETSC_TRUE; 863 snes->usesksp = PETSC_FALSE; 864 865 if (!snes->tolerancesset) { 866 snes->max_funcs = 30000; 867 snes->max_its = 10000; 868 } 869 870 ierr = PetscNewLog(snes,&qn);CHKERRQ(ierr); 871 snes->data = (void*) qn; 872 qn->m = 10; 873 qn->scaling = 1.0; 874 qn->U = NULL; 875 qn->V = NULL; 876 qn->dXtdF = NULL; 877 qn->dFtdX = NULL; 878 qn->dXdFmat = NULL; 879 qn->monitor = NULL; 880 qn->singlereduction = PETSC_TRUE; 881 qn->powell_gamma = 0.9999; 882 qn->scale_type = SNES_QN_SCALE_DEFAULT; 883 qn->restart_type = SNES_QN_RESTART_DEFAULT; 884 qn->type = SNES_QN_LBFGS; 885 886 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr); 887 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr); 888 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetType_C",SNESQNSetType_QN);CHKERRQ(ierr); 889 PetscFunctionReturn(0); 890 } 891