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