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