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 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++) dXtdF[j] = H(j, j); 221 } else { 222 ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr); 223 } 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 } else if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { 229 ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr); 230 } 231 } 232 233 ierr = VecCopy(D,Y);CHKERRQ(ierr); 234 235 if (qn->singlereduction) { 236 ierr = VecMDot(Y,l,dX,YtdX);CHKERRQ(ierr); 237 } 238 /* outward recursion starting at iteration k's update and working back */ 239 for (i=0; i<l; i++) { 240 k = (it-i-1)%l; 241 if (qn->singlereduction) { 242 /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */ 243 t = YtdX[k]; 244 for (j=0; j<i; j++) { 245 g = (it-j-1)%l; 246 t += -alpha[g]*H(g, k); 247 } 248 alpha[k] = t/H(k,k); 249 } else { 250 ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr); 251 alpha[k] = t/dXtdF[k]; 252 } 253 if (qn->monitor) { 254 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 255 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); 256 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 257 } 258 ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr); 259 } 260 261 if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { 262 ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 263 ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr); 264 ierr = SNES_KSPSolve(snes,snes->ksp,Y,W);CHKERRQ(ierr); 265 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 266 if (kspreason < 0) { 267 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 268 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 269 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 270 PetscFunctionReturn(0); 271 } 272 } 273 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 274 snes->linear_its += lits; 275 ierr = VecCopy(W, Y);CHKERRQ(ierr); 276 } else { 277 ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); 278 } 279 if (qn->singlereduction) { 280 ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr); 281 } 282 /* inward recursion starting at the first update and working forward */ 283 for (i = 0; i < l; i++) { 284 k = (it + i - l) % l; 285 if (qn->singlereduction) { 286 t = YtdX[k]; 287 for (j = 0; j < i; j++) { 288 g = (it + j - l) % l; 289 t += (alpha[g] - beta[g])*H(k, g); 290 } 291 beta[k] = t / H(k, k); 292 } else { 293 ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); 294 beta[k] = t / dXtdF[k]; 295 } 296 ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr); 297 if (qn->monitor) { 298 ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 299 ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); 300 ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); 301 } 302 } 303 PetscFunctionReturn(0); 304 } 305 306 #undef __FUNCT__ 307 #define __FUNCT__ "SNESSolve_QN" 308 static PetscErrorCode SNESSolve_QN(SNES snes) 309 { 310 PetscErrorCode ierr; 311 SNES_QN *qn = (SNES_QN*) snes->data; 312 Vec X,Xold; 313 Vec F,B; 314 Vec Y,FPC,D,Dold; 315 SNESConvergedReason reason; 316 PetscInt i, i_r; 317 PetscReal fnorm,xnorm,ynorm,gnorm; 318 PetscBool lssucceed,powell,periodic; 319 PetscScalar DolddotD,DolddotDold,DdotD,YdotD; 320 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 321 322 /* basically just a regular newton's method except for the application of the jacobian */ 323 324 PetscFunctionBegin; 325 F = snes->vec_func; /* residual vector */ 326 Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ 327 B = snes->vec_rhs; 328 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 = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 339 snes->iter = 0; 340 snes->norm = 0.; 341 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 342 if (!snes->vec_func_init_set) { 343 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 344 if (snes->domainerror) { 345 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 346 PetscFunctionReturn(0); 347 } 348 } else snes->vec_func_init_set = PETSC_FALSE; 349 350 if (!snes->norm_init_set) { 351 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 352 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 353 } else { 354 fnorm = snes->norm_init; 355 snes->norm_init_set = PETSC_FALSE; 356 } 357 358 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 359 snes->norm = fnorm; 360 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 361 SNESLogConvHistory(snes,fnorm,0); 362 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 363 364 /* set parameter for default relative tolerance convergence test */ 365 snes->ttol = fnorm*snes->rtol; 366 /* test convergence */ 367 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 368 if (snes->reason) PetscFunctionReturn(0); 369 370 /* composed solve */ 371 if (snes->pc && snes->pcside == PC_RIGHT) { 372 ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); 373 ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); 374 375 ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,B,0);CHKERRQ(ierr); 376 ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 377 ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,B,0);CHKERRQ(ierr); 378 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