Actual source code: stcg.c
1: #define PETSCKSP_DLL
3: #include src/ksp/ksp/kspimpl.h
4: #include src/ksp/ksp/impls/cg/stcg/stcg.h
8: /*@
9: KSPSTCGSetRadius - Sets the radius of the trust region.
11: Collective on KSP
13: Input Parameters:
14: + ksp - the iterative context
15: - radius - the trust region radius (Infinity is the default)
17: Options Database Key:
18: . -ksp_stcg_radius <r>
20: Level: advanced
22: .keywords: KSP, STCG, set, trust region radius
23: @*/
24: PetscErrorCode KSPSTCGSetRadius(KSP ksp,PetscReal radius)
25: {
26: PetscErrorCode ierr, (*f)(KSP, PetscReal);
30: if (radius <= 0.0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Tolerance must be positive");
31: PetscObjectQueryFunction((PetscObject)ksp, "KSPSTCGSetRadius_C", (void (**)(void))&f);
32: if (f) {
33: (*f)(ksp, radius);
34: }
35: return(0);
36: }
40: /*@
41: KSPSTCGGetQuadratic - Gets the value of the quadratic function, evaluated at the new iterate:
43: q(s) = g^T * s + 0.5 * s^T * H * s
45: which satisfies the trust region constraint
47: || s ||_M <= radius,
49: where
51: radius is the trust region radius,
52: g is the gradient vector, and
53: H is the Hessian matrix,
54: M is the positive definite preconditioner matrix.
56: Collective on KSP
58: Input Parameter:
59: . ksp - the iterative context
61: Output Parameter:
62: . quadratic - the quadratic function evaluated at the new iterate
64: Level: advanced
65: @*/
66: PetscErrorCode KSPSTCGGetQuadratic(KSP ksp,PetscReal *quadratic)
67: {
68: PetscErrorCode ierr,(*f)(KSP,PetscReal*);
72: PetscObjectQueryFunction((PetscObject)ksp, "KSPSTCGGetQuadratic_C", (void (**)(void))&f);
73: if (f) {
74: (*f)(ksp,quadratic);
75: }
76: return(0);
77: }
81: /*
82: KSPSolve_STCG - Use preconditioned conjugate gradient to compute
83: an approximate minimizer of the quadratic function
85: q(s) = g^T * s + .5 * s^T * H * s
87: subject to the trust region constraint
89: || s ||_M <= delta,
91: where
93: delta is the trust region radius,
94: g is the gradient vector, and
95: H is the Hessian matrix,
96: M is the positive definite preconditioner matrix.
98: KSPConvergedReason may be
99: $ KSP_CONVERGED_STCG_NEG_CURVE if convergence is reached along a negative curvature direction,
100: $ KSP_CONVERGED_STCG_CONSTRAINED if convergence is reached along a constrained step,
101: $ other KSP converged/diverged reasons
104: Notes:
105: The preconditioner supplied should be symmetric and positive definite.
106: */
107: PetscErrorCode KSPSolve_STCG(KSP ksp)
108: {
110: MatStructure pflag;
111: Mat Qmat, Mmat;
112: Vec r, z, p, w, d;
113: PC pc;
114: KSP_STCG *cg;
115: PetscReal zero = 0.0, pfive = 0.5, negone = -1.0;
116: PetscReal norm_r, norm_d, norm_dp1, norm_p, dMp;
117: PetscReal alpha, beta, kappa, rz, rzm1;
118: PetscReal radius;
119: PetscInt i, maxit;
120: #if defined(PETSC_USE_COMPLEX)
121: PetscScalar crz, ckappa, cquadratic;
122: #endif
123: PetscTruth diagonalscale;
126: PCDiagonalScale(ksp->pc,&diagonalscale);
127: if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",ksp->type_name);
129: cg = (KSP_STCG *)ksp->data;
130: radius = cg->radius;
131: maxit = ksp->max_it;
132: r = ksp->work[0];
133: z = ksp->work[1];
134: p = ksp->work[2];
135: w = ksp->work[3];
136: d = ksp->vec_sol;
137: pc = ksp->pc;
139: ksp->its = 0;
140: if (radius <= zero) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Input error: radius <= 0");
142: /* Initialize variables */
143: PCGetOperators(pc, &Qmat, &Mmat, &pflag);
145: VecSet(d, zero); /* d = 0 */
146: VecCopy(ksp->vec_rhs, r); /* r = rhs */
147: VecScale(r, negone); /* r = grad */
148: VecNorm(r, NORM_2, &norm_r); /* norm_r = |r| */
150: KSPLogResidualHistory(ksp, norm_r);
151: KSPMonitor(ksp, 0, norm_r);
152: ksp->rnorm = norm_r;
154: (*ksp->converged)(ksp, 0, norm_r, &ksp->reason, ksp->cnvP);
155: if (ksp->reason) return(0);
157: /* Compute the initial vectors */
158: PCApply(pc, r, z); /* z = M_{-1} r */
159: VecCopy(z, p); /* p = -z */
160: VecScale(p, negone);
161: #if defined(PETSC_USE_COMPLEX)
162: VecDot(r, z, &crz); rz = PetscRealPart(crz);
163: #else
164: VecDot(r, z, &rz); /* rz = r^T z */
165: #endif
167: dMp = 0;
168: norm_p = rz;
169: norm_d = 0;
171: /* Begin iterating */
172: for (i=0; i<=maxit; i++) {
173: ksp->its++;
175: MatMult(Qmat, p, w); /* w = Q * p */
176: #if defined(PETSC_USE_COMPLEX)
177: VecDot(p, w, &ckappa); kappa = PetscRealPart(ckappa);
178: #else
179: VecDot(p, w, &kappa); /* kappa = p^T w */
180: #endif
182: if (kappa <= zero) {
183: /* Direction of negative curvature, calculate intersection and sol */
185: alpha = (sqrt(dMp*dMp+norm_p*(radius-norm_d))-dMp)/norm_p;
186: VecAXPY(d, alpha, p); /* d = d + alpha p */
188: ksp->reason = KSP_CONVERGED_STCG_NEG_CURVE; /* negative curvature */
189: PetscInfo1(ksp, "KSPSolve_STCG: negative curvature: radius=%g\n", cg->radius);
190: break;
191: }
193: alpha = rz / kappa;
195: norm_dp1 = norm_d + 2.0*alpha*dMp + alpha*alpha*norm_p;
196: if (norm_dp1 >= radius) {
197: alpha = (sqrt(dMp*dMp+norm_p*(radius-norm_d))-dMp)/norm_p;
198: VecAXPY(d, alpha, p); /* d = d + alpha p */
200: ksp->reason = KSP_CONVERGED_STCG_CONSTRAINED; /* step */
201: PetscInfo1(ksp, "KSPSolve_STCG: constrained step: radius=%g\n",cg->radius);
202: break;
203: }
205: VecAXPY(d, alpha, p); /* d = d + alpha p */
206: VecAXPY(r, alpha, w); /* r = r + alpha w */
208: VecNorm(r, NORM_2, &norm_r);
209: ksp->rnorm = norm_r;
210: KSPLogResidualHistory(ksp, norm_r);
211: KSPMonitor(ksp, i+1, norm_r);
212: (*ksp->converged)(ksp, i+1, norm_r, &ksp->reason, ksp->cnvP);
213: if (ksp->reason) { /* convergence */
214: PetscInfo2(ksp,"KSPSolve_STCG: truncated step: rnorm=%g, radius=%g\n",norm_r,cg->radius);
215: break;
216: }
218: PCApply(pc, r, z);
220: rzm1 = rz;
221: #if defined(PETSC_USE_COMPLEX)
222: VecDot(r, z, &crz); rz = PetscRealPart(crz);
223: #else
224: VecDot(r, z, &rz);
225: #endif
226: beta = rz / rzm1;
228: VecAXPBY(p, negone, beta, z); /* p = beta p - z */
229: dMp = beta*dMp + alpha*norm_p;
230: norm_p = rz + beta*beta*norm_p;
231: norm_d = norm_dp1;
232: }
233: if (!ksp->reason) {
234: ksp->reason = KSP_DIVERGED_ITS;
235: }
237: /* Compute Q(x) */
238: MatMult(Qmat, d, p);
239: VecAXPBY(p, negone, pfive, ksp->vec_rhs);
240: #if defined(PETSC_USE_COMPLEX)
241: VecDot(d, p, &cquadratic); cg->quadratic = PetscRealPart(cquadratic);
242: #else
243: VecDot(d, p, &(cg->quadratic));
244: #endif
245: return(0);
246: }
250: PetscErrorCode KSPSetUp_STCG(KSP ksp)
251: {
255: /* This implementation of CG only handles left preconditioning
256: * so generate an error otherwise.
257: */
258: if (ksp->pc_side == PC_RIGHT) {
259: SETERRQ(PETSC_ERR_SUP, "No right preconditioning for KSPSTCG");
260: }
261: else if (ksp->pc_side == PC_SYMMETRIC) {
262: SETERRQ(PETSC_ERR_SUP, "No symmetric preconditioning for KSPSTCG");
263: }
265: /* get work vectors needed by CG */
266: KSPDefaultGetWork(ksp, 4);
267: return(0);
268: }
272: PetscErrorCode KSPDestroy_STCG(KSP ksp)
273: {
274: KSP_STCG *cgP = (KSP_STCG *)ksp->data;
278: KSPDefaultFreeWork(ksp);
280: /* Free the context variable */
281: PetscFree(cgP);
282: return(0);
283: }
288: PetscErrorCode KSPSTCGSetRadius_STCG(KSP ksp,PetscReal radius)
289: {
290: KSP_STCG *cgP = (KSP_STCG *)ksp->data;
293: cgP->radius = radius;
294: return(0);
295: }
301: PetscErrorCode KSPSTCGGetQuadratic_STCG(KSP ksp,PetscReal *quadratic)
302: {
303: KSP_STCG *cgP = (KSP_STCG *)ksp->data;
306: *quadratic = cgP->quadratic;
307: return(0);
308: }
313: PetscErrorCode KSPSetFromOptions_STCG(KSP ksp)
314: {
316: KSP_STCG *cgP = (KSP_STCG *)ksp->data;
317: PetscReal radius;
318: PetscTruth flg;
321: PetscOptionsHead("KSP STCG options");
322: PetscOptionsReal("-ksp_stcg_radius", "Trust Region Radius", "KSPSTCGSetRadius", cgP->radius, &radius, &flg);
323: if (flg) { KSPSTCGSetRadius(ksp, radius); }
324: PetscOptionsTail();
325: return(0);
326: }
328: /*MC
329: KSPSTCG - Code to run conjugate gradient method subject to a constraint
330: on the solution norm. This is used in Trust Region methods for
331: nonlinear equations, SNESTR
333: Options Database Keys:
334: . -ksp_stcg_radius <r> - Trust Region Radius
336: Notes: This is rarely used directly
338: Level: developer
340: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP, KSPSTCGSetRadius()
341: KSPSTCGGetQuadratic()
342: M*/
347: PetscErrorCode KSPCreate_STCG(KSP ksp)
348: {
350: KSP_STCG *cg;
353: PetscNew(KSP_STCG, &cg);
354: PetscLogObjectMemory(ksp, sizeof(KSP_STCG));
355: cg->radius = PETSC_MAX;
356: cg->quadratic = 0;
357: ksp->data = (void *)cg;
358: ksp->pc_side = PC_LEFT;
360: /* Sets the functions that are associated with this data structure
361: * (in C++ this is the same as defining virtual functions)
362: */
363: ksp->ops->setup = KSPSetUp_STCG;
364: ksp->ops->solve = KSPSolve_STCG;
365: ksp->ops->destroy = KSPDestroy_STCG;
366: ksp->ops->setfromoptions = KSPSetFromOptions_STCG;
367: ksp->ops->buildsolution = KSPDefaultBuildSolution;
368: ksp->ops->buildresidual = KSPDefaultBuildResidual;
369: ksp->ops->view = 0;
371: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPSTCGGetQuadratic_C",
372: "KSPSTCGGetQuadratic_STCG",
373: KSPSTCGGetQuadratic_STCG);
374: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPSTCGSetRadius_C",
375: "KSPSTCGSetRadius_STCG",
376: KSPSTCGSetRadius_STCG);
377: return(0);
378: }