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