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