Actual source code: lcl.c
1: #include <../src/tao/pde_constrained/impls/lcl/lcl.h>
2: static PetscErrorCode LCLComputeLagrangianAndGradient(TaoLineSearch, Vec, PetscReal *, Vec, void *);
3: static PetscErrorCode LCLComputeAugmentedLagrangianAndGradient(TaoLineSearch, Vec, PetscReal *, Vec, void *);
4: static PetscErrorCode LCLScatter(TAO_LCL *, Vec, Vec, Vec);
5: static PetscErrorCode LCLGather(TAO_LCL *, Vec, Vec, Vec);
7: static PetscErrorCode TaoDestroy_LCL(Tao tao)
8: {
9: TAO_LCL *lclP = (TAO_LCL *)tao->data;
11: PetscFunctionBegin;
12: if (tao->setupcalled) {
13: PetscCall(MatDestroy(&lclP->R));
14: PetscCall(VecDestroy(&lclP->lambda));
15: PetscCall(VecDestroy(&lclP->lambda0));
16: PetscCall(VecDestroy(&lclP->WL));
17: PetscCall(VecDestroy(&lclP->W));
18: PetscCall(VecDestroy(&lclP->X0));
19: PetscCall(VecDestroy(&lclP->G0));
20: PetscCall(VecDestroy(&lclP->GL));
21: PetscCall(VecDestroy(&lclP->GAugL));
22: PetscCall(VecDestroy(&lclP->dbar));
23: PetscCall(VecDestroy(&lclP->U));
24: PetscCall(VecDestroy(&lclP->U0));
25: PetscCall(VecDestroy(&lclP->V));
26: PetscCall(VecDestroy(&lclP->V0));
27: PetscCall(VecDestroy(&lclP->V1));
28: PetscCall(VecDestroy(&lclP->GU));
29: PetscCall(VecDestroy(&lclP->GV));
30: PetscCall(VecDestroy(&lclP->GU0));
31: PetscCall(VecDestroy(&lclP->GV0));
32: PetscCall(VecDestroy(&lclP->GL_U));
33: PetscCall(VecDestroy(&lclP->GL_V));
34: PetscCall(VecDestroy(&lclP->GAugL_U));
35: PetscCall(VecDestroy(&lclP->GAugL_V));
36: PetscCall(VecDestroy(&lclP->GL_U0));
37: PetscCall(VecDestroy(&lclP->GL_V0));
38: PetscCall(VecDestroy(&lclP->GAugL_U0));
39: PetscCall(VecDestroy(&lclP->GAugL_V0));
40: PetscCall(VecDestroy(&lclP->DU));
41: PetscCall(VecDestroy(&lclP->DV));
42: PetscCall(VecDestroy(&lclP->WU));
43: PetscCall(VecDestroy(&lclP->WV));
44: PetscCall(VecDestroy(&lclP->g1));
45: PetscCall(VecDestroy(&lclP->g2));
46: PetscCall(VecDestroy(&lclP->con1));
48: PetscCall(VecDestroy(&lclP->r));
49: PetscCall(VecDestroy(&lclP->s));
51: PetscCall(ISDestroy(&tao->state_is));
52: PetscCall(ISDestroy(&tao->design_is));
54: PetscCall(VecScatterDestroy(&lclP->state_scatter));
55: PetscCall(VecScatterDestroy(&lclP->design_scatter));
56: }
57: PetscCall(MatDestroy(&lclP->R));
58: PetscCall(KSPDestroy(&tao->ksp));
59: PetscCall(PetscFree(tao->data));
60: PetscFunctionReturn(PETSC_SUCCESS);
61: }
63: static PetscErrorCode TaoSetFromOptions_LCL(Tao tao, PetscOptionItems *PetscOptionsObject)
64: {
65: TAO_LCL *lclP = (TAO_LCL *)tao->data;
67: PetscFunctionBegin;
68: PetscOptionsHeadBegin(PetscOptionsObject, "Linearly-Constrained Augmented Lagrangian Method for PDE-constrained optimization");
69: PetscCall(PetscOptionsReal("-tao_lcl_eps1", "epsilon 1 tolerance", "", lclP->eps1, &lclP->eps1, NULL));
70: PetscCall(PetscOptionsReal("-tao_lcl_eps2", "epsilon 2 tolerance", "", lclP->eps2, &lclP->eps2, NULL));
71: PetscCall(PetscOptionsReal("-tao_lcl_rho0", "init value for rho", "", lclP->rho0, &lclP->rho0, NULL));
72: PetscCall(PetscOptionsReal("-tao_lcl_rhomax", "max value for rho", "", lclP->rhomax, &lclP->rhomax, NULL));
73: lclP->phase2_niter = 1;
74: PetscCall(PetscOptionsInt("-tao_lcl_phase2_niter", "Number of phase 2 iterations in LCL algorithm", "", lclP->phase2_niter, &lclP->phase2_niter, NULL));
75: lclP->verbose = PETSC_FALSE;
76: PetscCall(PetscOptionsBool("-tao_lcl_verbose", "Print verbose output", "", lclP->verbose, &lclP->verbose, NULL));
77: lclP->tau[0] = lclP->tau[1] = lclP->tau[2] = lclP->tau[3] = 1.0e-4;
78: PetscCall(PetscOptionsReal("-tao_lcl_tola", "Tolerance for first forward solve", "", lclP->tau[0], &lclP->tau[0], NULL));
79: PetscCall(PetscOptionsReal("-tao_lcl_tolb", "Tolerance for first adjoint solve", "", lclP->tau[1], &lclP->tau[1], NULL));
80: PetscCall(PetscOptionsReal("-tao_lcl_tolc", "Tolerance for second forward solve", "", lclP->tau[2], &lclP->tau[2], NULL));
81: PetscCall(PetscOptionsReal("-tao_lcl_told", "Tolerance for second adjoint solve", "", lclP->tau[3], &lclP->tau[3], NULL));
82: PetscOptionsHeadEnd();
83: PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
84: PetscCall(MatSetFromOptions(lclP->R));
85: PetscFunctionReturn(PETSC_SUCCESS);
86: }
88: static PetscErrorCode TaoView_LCL(Tao tao, PetscViewer viewer)
89: {
90: return PETSC_SUCCESS;
91: }
93: static PetscErrorCode TaoSetup_LCL(Tao tao)
94: {
95: TAO_LCL *lclP = (TAO_LCL *)tao->data;
96: PetscInt lo, hi, nlocalstate, nlocaldesign;
97: IS is_state, is_design;
99: PetscFunctionBegin;
100: PetscCheck(tao->state_is, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "LCL Solver requires an initial state index set -- use TaoSetStateIS()");
101: PetscCall(VecDuplicate(tao->solution, &tao->gradient));
102: PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
103: PetscCall(VecDuplicate(tao->solution, &lclP->W));
104: PetscCall(VecDuplicate(tao->solution, &lclP->X0));
105: PetscCall(VecDuplicate(tao->solution, &lclP->G0));
106: PetscCall(VecDuplicate(tao->solution, &lclP->GL));
107: PetscCall(VecDuplicate(tao->solution, &lclP->GAugL));
109: PetscCall(VecDuplicate(tao->constraints, &lclP->lambda));
110: PetscCall(VecDuplicate(tao->constraints, &lclP->WL));
111: PetscCall(VecDuplicate(tao->constraints, &lclP->lambda0));
112: PetscCall(VecDuplicate(tao->constraints, &lclP->con1));
114: PetscCall(VecSet(lclP->lambda, 0.0));
116: PetscCall(VecGetSize(tao->solution, &lclP->n));
117: PetscCall(VecGetSize(tao->constraints, &lclP->m));
119: PetscCall(VecCreate(((PetscObject)tao)->comm, &lclP->U));
120: PetscCall(VecCreate(((PetscObject)tao)->comm, &lclP->V));
121: PetscCall(ISGetLocalSize(tao->state_is, &nlocalstate));
122: PetscCall(ISGetLocalSize(tao->design_is, &nlocaldesign));
123: PetscCall(VecSetSizes(lclP->U, nlocalstate, lclP->m));
124: PetscCall(VecSetSizes(lclP->V, nlocaldesign, lclP->n - lclP->m));
125: PetscCall(VecSetType(lclP->U, ((PetscObject)(tao->solution))->type_name));
126: PetscCall(VecSetType(lclP->V, ((PetscObject)(tao->solution))->type_name));
127: PetscCall(VecSetFromOptions(lclP->U));
128: PetscCall(VecSetFromOptions(lclP->V));
129: PetscCall(VecDuplicate(lclP->U, &lclP->DU));
130: PetscCall(VecDuplicate(lclP->U, &lclP->U0));
131: PetscCall(VecDuplicate(lclP->U, &lclP->GU));
132: PetscCall(VecDuplicate(lclP->U, &lclP->GU0));
133: PetscCall(VecDuplicate(lclP->U, &lclP->GAugL_U));
134: PetscCall(VecDuplicate(lclP->U, &lclP->GL_U));
135: PetscCall(VecDuplicate(lclP->U, &lclP->GAugL_U0));
136: PetscCall(VecDuplicate(lclP->U, &lclP->GL_U0));
137: PetscCall(VecDuplicate(lclP->U, &lclP->WU));
138: PetscCall(VecDuplicate(lclP->U, &lclP->r));
139: PetscCall(VecDuplicate(lclP->V, &lclP->V0));
140: PetscCall(VecDuplicate(lclP->V, &lclP->V1));
141: PetscCall(VecDuplicate(lclP->V, &lclP->DV));
142: PetscCall(VecDuplicate(lclP->V, &lclP->s));
143: PetscCall(VecDuplicate(lclP->V, &lclP->GV));
144: PetscCall(VecDuplicate(lclP->V, &lclP->GV0));
145: PetscCall(VecDuplicate(lclP->V, &lclP->dbar));
146: PetscCall(VecDuplicate(lclP->V, &lclP->GAugL_V));
147: PetscCall(VecDuplicate(lclP->V, &lclP->GL_V));
148: PetscCall(VecDuplicate(lclP->V, &lclP->GAugL_V0));
149: PetscCall(VecDuplicate(lclP->V, &lclP->GL_V0));
150: PetscCall(VecDuplicate(lclP->V, &lclP->WV));
151: PetscCall(VecDuplicate(lclP->V, &lclP->g1));
152: PetscCall(VecDuplicate(lclP->V, &lclP->g2));
154: /* create scatters for state, design subvecs */
155: PetscCall(VecGetOwnershipRange(lclP->U, &lo, &hi));
156: PetscCall(ISCreateStride(((PetscObject)lclP->U)->comm, hi - lo, lo, 1, &is_state));
157: PetscCall(VecGetOwnershipRange(lclP->V, &lo, &hi));
158: if (0) {
159: PetscInt sizeU, sizeV;
160: PetscCall(VecGetSize(lclP->U, &sizeU));
161: PetscCall(VecGetSize(lclP->V, &sizeV));
162: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "size(U)=%" PetscInt_FMT ", size(V)=%" PetscInt_FMT "\n", sizeU, sizeV));
163: }
164: PetscCall(ISCreateStride(((PetscObject)lclP->V)->comm, hi - lo, lo, 1, &is_design));
165: PetscCall(VecScatterCreate(tao->solution, tao->state_is, lclP->U, is_state, &lclP->state_scatter));
166: PetscCall(VecScatterCreate(tao->solution, tao->design_is, lclP->V, is_design, &lclP->design_scatter));
167: PetscCall(ISDestroy(&is_state));
168: PetscCall(ISDestroy(&is_design));
169: PetscFunctionReturn(PETSC_SUCCESS);
170: }
172: static PetscErrorCode TaoSolve_LCL(Tao tao)
173: {
174: TAO_LCL *lclP = (TAO_LCL *)tao->data;
175: PetscInt phase2_iter, nlocal, its;
176: TaoLineSearchConvergedReason ls_reason = TAOLINESEARCH_CONTINUE_ITERATING;
177: PetscReal step = 1.0, f, descent, aldescent;
178: PetscReal cnorm, mnorm;
179: PetscReal adec, r2, rGL_U, rWU;
180: PetscBool set, pset, flag, pflag, symmetric;
182: PetscFunctionBegin;
183: lclP->rho = lclP->rho0;
184: PetscCall(VecGetLocalSize(lclP->U, &nlocal));
185: PetscCall(VecGetLocalSize(lclP->V, &nlocal));
186: PetscCall(MatSetSizes(lclP->R, nlocal, nlocal, lclP->n - lclP->m, lclP->n - lclP->m));
187: PetscCall(MatLMVMAllocate(lclP->R, lclP->V, lclP->V));
188: lclP->recompute_jacobian_flag = PETSC_TRUE;
190: /* Scatter to U,V */
191: PetscCall(LCLScatter(lclP, tao->solution, lclP->U, lclP->V));
193: /* Evaluate Function, Gradient, Constraints, and Jacobian */
194: PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
195: PetscCall(TaoComputeJacobianState(tao, tao->solution, tao->jacobian_state, tao->jacobian_state_pre, tao->jacobian_state_inv));
196: PetscCall(TaoComputeJacobianDesign(tao, tao->solution, tao->jacobian_design));
197: PetscCall(TaoComputeConstraints(tao, tao->solution, tao->constraints));
199: /* Scatter gradient to GU,GV */
200: PetscCall(LCLScatter(lclP, tao->gradient, lclP->GU, lclP->GV));
202: /* Evaluate Lagrangian function and gradient */
203: /* p0 */
204: PetscCall(VecSet(lclP->lambda, 0.0)); /* Initial guess in CG */
205: PetscCall(MatIsSymmetricKnown(tao->jacobian_state, &set, &flag));
206: if (tao->jacobian_state_pre) {
207: PetscCall(MatIsSymmetricKnown(tao->jacobian_state_pre, &pset, &pflag));
208: } else {
209: pset = pflag = PETSC_TRUE;
210: }
211: if (set && pset && flag && pflag) symmetric = PETSC_TRUE;
212: else symmetric = PETSC_FALSE;
214: lclP->solve_type = LCL_ADJOINT2;
215: if (tao->jacobian_state_inv) {
216: if (symmetric) {
217: PetscCall(MatMult(tao->jacobian_state_inv, lclP->GU, lclP->lambda));
218: } else {
219: PetscCall(MatMultTranspose(tao->jacobian_state_inv, lclP->GU, lclP->lambda));
220: }
221: } else {
222: PetscCall(KSPSetOperators(tao->ksp, tao->jacobian_state, tao->jacobian_state_pre));
223: if (symmetric) {
224: PetscCall(KSPSolve(tao->ksp, lclP->GU, lclP->lambda));
225: } else {
226: PetscCall(KSPSolveTranspose(tao->ksp, lclP->GU, lclP->lambda));
227: }
228: PetscCall(KSPGetIterationNumber(tao->ksp, &its));
229: tao->ksp_its += its;
230: tao->ksp_tot_its += its;
231: }
232: PetscCall(VecCopy(lclP->lambda, lclP->lambda0));
233: PetscCall(LCLComputeAugmentedLagrangianAndGradient(tao->linesearch, tao->solution, &lclP->aug, lclP->GAugL, tao));
235: PetscCall(LCLScatter(lclP, lclP->GL, lclP->GL_U, lclP->GL_V));
236: PetscCall(LCLScatter(lclP, lclP->GAugL, lclP->GAugL_U, lclP->GAugL_V));
238: /* Evaluate constraint norm */
239: PetscCall(VecNorm(tao->constraints, NORM_2, &cnorm));
240: PetscCall(VecNorm(lclP->GAugL, NORM_2, &mnorm));
242: /* Monitor convergence */
243: tao->reason = TAO_CONTINUE_ITERATING;
244: PetscCall(TaoLogConvergenceHistory(tao, f, mnorm, cnorm, tao->ksp_its));
245: PetscCall(TaoMonitor(tao, tao->niter, f, mnorm, cnorm, step));
246: PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
248: while (tao->reason == TAO_CONTINUE_ITERATING) {
249: /* Call general purpose update function */
250: PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);
251: tao->ksp_its = 0;
252: /* Compute a descent direction for the linearly constrained subproblem
253: minimize f(u+du, v+dv)
254: s.t. A(u0,v0)du + B(u0,v0)dv = -g(u0,v0) */
256: /* Store the points around the linearization */
257: PetscCall(VecCopy(lclP->U, lclP->U0));
258: PetscCall(VecCopy(lclP->V, lclP->V0));
259: PetscCall(VecCopy(lclP->GU, lclP->GU0));
260: PetscCall(VecCopy(lclP->GV, lclP->GV0));
261: PetscCall(VecCopy(lclP->GAugL_U, lclP->GAugL_U0));
262: PetscCall(VecCopy(lclP->GAugL_V, lclP->GAugL_V0));
263: PetscCall(VecCopy(lclP->GL_U, lclP->GL_U0));
264: PetscCall(VecCopy(lclP->GL_V, lclP->GL_V0));
266: lclP->aug0 = lclP->aug;
267: lclP->lgn0 = lclP->lgn;
269: /* Given the design variables, we need to project the current iterate
270: onto the linearized constraint. We choose to fix the design variables
271: and solve the linear system for the state variables. The resulting
272: point is the Newton direction */
274: /* Solve r = A\con */
275: lclP->solve_type = LCL_FORWARD1;
276: PetscCall(VecSet(lclP->r, 0.0)); /* Initial guess in CG */
278: if (tao->jacobian_state_inv) {
279: PetscCall(MatMult(tao->jacobian_state_inv, tao->constraints, lclP->r));
280: } else {
281: PetscCall(KSPSetOperators(tao->ksp, tao->jacobian_state, tao->jacobian_state_pre));
282: PetscCall(KSPSolve(tao->ksp, tao->constraints, lclP->r));
283: PetscCall(KSPGetIterationNumber(tao->ksp, &its));
284: tao->ksp_its += its;
285: tao->ksp_tot_its += tao->ksp_its;
286: }
288: /* Set design step direction dv to zero */
289: PetscCall(VecSet(lclP->s, 0.0));
291: /*
292: Check sufficient descent for constraint merit function .5*||con||^2
293: con' Ak r >= eps1 ||r||^(2+eps2)
294: */
296: /* Compute WU= Ak' * con */
297: if (symmetric) {
298: PetscCall(MatMult(tao->jacobian_state, tao->constraints, lclP->WU));
299: } else {
300: PetscCall(MatMultTranspose(tao->jacobian_state, tao->constraints, lclP->WU));
301: }
302: /* Compute r * Ak' * con */
303: PetscCall(VecDot(lclP->r, lclP->WU, &rWU));
305: /* compute ||r||^(2+eps2) */
306: PetscCall(VecNorm(lclP->r, NORM_2, &r2));
307: r2 = PetscPowScalar(r2, 2.0 + lclP->eps2);
308: adec = lclP->eps1 * r2;
310: if (rWU < adec) {
311: PetscCall(PetscInfo(tao, "Newton direction not descent for constraint, feasibility phase required\n"));
312: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Newton direction not descent for constraint: %g -- using steepest descent\n", (double)descent));
314: PetscCall(PetscInfo(tao, "Using steepest descent direction instead.\n"));
315: PetscCall(VecSet(lclP->r, 0.0));
316: PetscCall(VecAXPY(lclP->r, -1.0, lclP->WU));
317: PetscCall(VecDot(lclP->r, lclP->r, &rWU));
318: PetscCall(VecNorm(lclP->r, NORM_2, &r2));
319: r2 = PetscPowScalar(r2, 2.0 + lclP->eps2);
320: PetscCall(VecDot(lclP->r, lclP->GAugL_U, &descent));
321: adec = lclP->eps1 * r2;
322: }
324: /*
325: Check descent for aug. lagrangian
326: r' (GUk - Ak'*yk - rho*Ak'*con) <= -eps1 ||r||^(2+eps2)
327: GL_U = GUk - Ak'*yk
328: WU = Ak'*con
329: adec=eps1||r||^(2+eps2)
331: ==>
332: Check r'GL_U - rho*r'WU <= adec
333: */
335: PetscCall(VecDot(lclP->r, lclP->GL_U, &rGL_U));
336: aldescent = rGL_U - lclP->rho * rWU;
337: if (aldescent > -adec) {
338: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Newton direction not descent for augmented Lagrangian: %g", (double)aldescent));
339: PetscCall(PetscInfo(tao, "Newton direction not descent for augmented Lagrangian: %g\n", (double)aldescent));
340: lclP->rho = (rGL_U - adec) / rWU;
341: if (lclP->rho > lclP->rhomax) {
342: lclP->rho = lclP->rhomax;
343: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "rho=%g > rhomax, case not implemented. Increase rhomax (-tao_lcl_rhomax)", (double)lclP->rho);
344: }
345: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Increasing penalty parameter to %g\n", (double)lclP->rho));
346: PetscCall(PetscInfo(tao, " Increasing penalty parameter to %g\n", (double)lclP->rho));
347: }
349: PetscCall(LCLComputeAugmentedLagrangianAndGradient(tao->linesearch, tao->solution, &lclP->aug, lclP->GAugL, tao));
350: PetscCall(LCLScatter(lclP, lclP->GL, lclP->GL_U, lclP->GL_V));
351: PetscCall(LCLScatter(lclP, lclP->GAugL, lclP->GAugL_U, lclP->GAugL_V));
353: /* We now minimize the augmented Lagrangian along the Newton direction */
354: PetscCall(VecScale(lclP->r, -1.0));
355: PetscCall(LCLGather(lclP, lclP->r, lclP->s, tao->stepdirection));
356: PetscCall(VecScale(lclP->r, -1.0));
357: PetscCall(LCLGather(lclP, lclP->GAugL_U0, lclP->GAugL_V0, lclP->GAugL));
358: PetscCall(LCLGather(lclP, lclP->U0, lclP->V0, lclP->X0));
360: lclP->recompute_jacobian_flag = PETSC_TRUE;
362: PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0));
363: PetscCall(TaoLineSearchSetType(tao->linesearch, TAOLINESEARCHMT));
364: PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
365: PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &lclP->aug, lclP->GAugL, tao->stepdirection, &step, &ls_reason));
366: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Steplength = %g\n", (double)step));
368: PetscCall(LCLScatter(lclP, tao->solution, lclP->U, lclP->V));
369: PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
370: PetscCall(LCLScatter(lclP, tao->gradient, lclP->GU, lclP->GV));
372: PetscCall(LCLScatter(lclP, lclP->GAugL, lclP->GAugL_U, lclP->GAugL_V));
374: /* Check convergence */
375: PetscCall(VecNorm(lclP->GAugL, NORM_2, &mnorm));
376: PetscCall(VecNorm(tao->constraints, NORM_2, &cnorm));
377: PetscCall(TaoLogConvergenceHistory(tao, f, mnorm, cnorm, tao->ksp_its));
378: PetscCall(TaoMonitor(tao, tao->niter, f, mnorm, cnorm, step));
379: PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
380: if (tao->reason != TAO_CONTINUE_ITERATING) break;
382: /* TODO: use a heuristic to choose how many iterations should be performed within phase 2 */
383: for (phase2_iter = 0; phase2_iter < lclP->phase2_niter; phase2_iter++) {
384: /* We now minimize the objective function starting from the fraction of
385: the Newton point accepted by applying one step of a reduced-space
386: method. The optimization problem is:
388: minimize f(u+du, v+dv)
389: s. t. A(u0,v0)du + B(u0,v0)du = -alpha g(u0,v0)
391: In particular, we have that
392: du = -inv(A)*(Bdv + alpha g) */
394: PetscCall(TaoComputeJacobianState(tao, lclP->X0, tao->jacobian_state, tao->jacobian_state_pre, tao->jacobian_state_inv));
395: PetscCall(TaoComputeJacobianDesign(tao, lclP->X0, tao->jacobian_design));
397: /* Store V and constraints */
398: PetscCall(VecCopy(lclP->V, lclP->V1));
399: PetscCall(VecCopy(tao->constraints, lclP->con1));
401: /* Compute multipliers */
402: /* p1 */
403: PetscCall(VecSet(lclP->lambda, 0.0)); /* Initial guess in CG */
404: lclP->solve_type = LCL_ADJOINT1;
405: PetscCall(MatIsSymmetricKnown(tao->jacobian_state, &set, &flag));
406: if (tao->jacobian_state_pre) {
407: PetscCall(MatIsSymmetricKnown(tao->jacobian_state_pre, &pset, &pflag));
408: } else {
409: pset = pflag = PETSC_TRUE;
410: }
411: if (set && pset && flag && pflag) symmetric = PETSC_TRUE;
412: else symmetric = PETSC_FALSE;
414: if (tao->jacobian_state_inv) {
415: if (symmetric) {
416: PetscCall(MatMult(tao->jacobian_state_inv, lclP->GAugL_U, lclP->lambda));
417: } else {
418: PetscCall(MatMultTranspose(tao->jacobian_state_inv, lclP->GAugL_U, lclP->lambda));
419: }
420: } else {
421: if (symmetric) {
422: PetscCall(KSPSolve(tao->ksp, lclP->GAugL_U, lclP->lambda));
423: } else {
424: PetscCall(KSPSolveTranspose(tao->ksp, lclP->GAugL_U, lclP->lambda));
425: }
426: PetscCall(KSPGetIterationNumber(tao->ksp, &its));
427: tao->ksp_its += its;
428: tao->ksp_tot_its += its;
429: }
430: PetscCall(MatMultTranspose(tao->jacobian_design, lclP->lambda, lclP->g1));
431: PetscCall(VecAXPY(lclP->g1, -1.0, lclP->GAugL_V));
433: /* Compute the limited-memory quasi-newton direction */
434: if (tao->niter > 0) {
435: PetscCall(MatSolve(lclP->R, lclP->g1, lclP->s));
436: PetscCall(VecDot(lclP->s, lclP->g1, &descent));
437: if (descent <= 0) {
438: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Reduced-space direction not descent: %g\n", (double)descent));
439: PetscCall(VecCopy(lclP->g1, lclP->s));
440: }
441: } else {
442: PetscCall(VecCopy(lclP->g1, lclP->s));
443: }
444: PetscCall(VecScale(lclP->g1, -1.0));
446: /* Recover the full space direction */
447: PetscCall(MatMult(tao->jacobian_design, lclP->s, lclP->WU));
448: /* PetscCall(VecSet(lclP->r,0.0)); */ /* Initial guess in CG */
449: lclP->solve_type = LCL_FORWARD2;
450: if (tao->jacobian_state_inv) {
451: PetscCall(MatMult(tao->jacobian_state_inv, lclP->WU, lclP->r));
452: } else {
453: PetscCall(KSPSolve(tao->ksp, lclP->WU, lclP->r));
454: PetscCall(KSPGetIterationNumber(tao->ksp, &its));
455: tao->ksp_its += its;
456: tao->ksp_tot_its += its;
457: }
459: /* We now minimize the augmented Lagrangian along the direction -r,s */
460: PetscCall(VecScale(lclP->r, -1.0));
461: PetscCall(LCLGather(lclP, lclP->r, lclP->s, tao->stepdirection));
462: PetscCall(VecScale(lclP->r, -1.0));
463: lclP->recompute_jacobian_flag = PETSC_TRUE;
465: PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0));
466: PetscCall(TaoLineSearchSetType(tao->linesearch, TAOLINESEARCHMT));
467: PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
468: PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &lclP->aug, lclP->GAugL, tao->stepdirection, &step, &ls_reason));
469: if (lclP->verbose) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Reduced-space steplength = %g\n", (double)step));
471: PetscCall(LCLScatter(lclP, tao->solution, lclP->U, lclP->V));
472: PetscCall(LCLScatter(lclP, lclP->GL, lclP->GL_U, lclP->GL_V));
473: PetscCall(LCLScatter(lclP, lclP->GAugL, lclP->GAugL_U, lclP->GAugL_V));
474: PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
475: PetscCall(LCLScatter(lclP, tao->gradient, lclP->GU, lclP->GV));
477: /* Compute the reduced gradient at the new point */
479: PetscCall(TaoComputeJacobianState(tao, lclP->X0, tao->jacobian_state, tao->jacobian_state_pre, tao->jacobian_state_inv));
480: PetscCall(TaoComputeJacobianDesign(tao, lclP->X0, tao->jacobian_design));
482: /* p2 */
483: /* Compute multipliers, using lambda-rho*con as an initial guess in PCG */
484: if (phase2_iter == 0) {
485: PetscCall(VecWAXPY(lclP->lambda, -lclP->rho, lclP->con1, lclP->lambda0));
486: } else {
487: PetscCall(VecAXPY(lclP->lambda, -lclP->rho, tao->constraints));
488: }
490: PetscCall(MatIsSymmetricKnown(tao->jacobian_state, &set, &flag));
491: if (tao->jacobian_state_pre) {
492: PetscCall(MatIsSymmetricKnown(tao->jacobian_state_pre, &pset, &pflag));
493: } else {
494: pset = pflag = PETSC_TRUE;
495: }
496: if (set && pset && flag && pflag) symmetric = PETSC_TRUE;
497: else symmetric = PETSC_FALSE;
499: lclP->solve_type = LCL_ADJOINT2;
500: if (tao->jacobian_state_inv) {
501: if (symmetric) {
502: PetscCall(MatMult(tao->jacobian_state_inv, lclP->GU, lclP->lambda));
503: } else {
504: PetscCall(MatMultTranspose(tao->jacobian_state_inv, lclP->GU, lclP->lambda));
505: }
506: } else {
507: if (symmetric) {
508: PetscCall(KSPSolve(tao->ksp, lclP->GU, lclP->lambda));
509: } else {
510: PetscCall(KSPSolveTranspose(tao->ksp, lclP->GU, lclP->lambda));
511: }
512: PetscCall(KSPGetIterationNumber(tao->ksp, &its));
513: tao->ksp_its += its;
514: tao->ksp_tot_its += its;
515: }
517: PetscCall(MatMultTranspose(tao->jacobian_design, lclP->lambda, lclP->g2));
518: PetscCall(VecAXPY(lclP->g2, -1.0, lclP->GV));
520: PetscCall(VecScale(lclP->g2, -1.0));
522: /* Update the quasi-newton approximation */
523: PetscCall(MatLMVMUpdate(lclP->R, lclP->V, lclP->g2));
524: /* Use "-tao_ls_type gpcg -tao_ls_ftol 0 -tao_lmm_broyden_phi 0.0 -tao_lmm_scale_type scalar" to obtain agreement with MATLAB code */
525: }
527: PetscCall(VecCopy(lclP->lambda, lclP->lambda0));
529: /* Evaluate Function, Gradient, Constraints, and Jacobian */
530: PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
531: PetscCall(LCLScatter(lclP, tao->solution, lclP->U, lclP->V));
532: PetscCall(LCLScatter(lclP, tao->gradient, lclP->GU, lclP->GV));
534: PetscCall(TaoComputeJacobianState(tao, tao->solution, tao->jacobian_state, tao->jacobian_state_pre, tao->jacobian_state_inv));
535: PetscCall(TaoComputeJacobianDesign(tao, tao->solution, tao->jacobian_design));
536: PetscCall(TaoComputeConstraints(tao, tao->solution, tao->constraints));
538: PetscCall(LCLComputeAugmentedLagrangianAndGradient(tao->linesearch, tao->solution, &lclP->aug, lclP->GAugL, tao));
540: PetscCall(VecNorm(lclP->GAugL, NORM_2, &mnorm));
542: /* Evaluate constraint norm */
543: PetscCall(VecNorm(tao->constraints, NORM_2, &cnorm));
545: /* Monitor convergence */
546: tao->niter++;
547: PetscCall(TaoLogConvergenceHistory(tao, f, mnorm, cnorm, tao->ksp_its));
548: PetscCall(TaoMonitor(tao, tao->niter, f, mnorm, cnorm, step));
549: PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
550: }
551: PetscFunctionReturn(PETSC_SUCCESS);
552: }
554: /*MC
555: TAOLCL - linearly constrained lagrangian method for pde-constrained optimization
557: + -tao_lcl_eps1 - epsilon 1 tolerance
558: . -tao_lcl_eps2","epsilon 2 tolerance","",lclP->eps2,&lclP->eps2,NULL);
559: . -tao_lcl_rho0","init value for rho","",lclP->rho0,&lclP->rho0,NULL);
560: . -tao_lcl_rhomax","max value for rho","",lclP->rhomax,&lclP->rhomax,NULL);
561: . -tao_lcl_phase2_niter - Number of phase 2 iterations in LCL algorithm
562: . -tao_lcl_verbose - Print verbose output if True
563: . -tao_lcl_tola - Tolerance for first forward solve
564: . -tao_lcl_tolb - Tolerance for first adjoint solve
565: . -tao_lcl_tolc - Tolerance for second forward solve
566: - -tao_lcl_told - Tolerance for second adjoint solve
568: Level: beginner
569: M*/
570: PETSC_EXTERN PetscErrorCode TaoCreate_LCL(Tao tao)
571: {
572: TAO_LCL *lclP;
573: const char *morethuente_type = TAOLINESEARCHMT;
575: PetscFunctionBegin;
576: tao->ops->setup = TaoSetup_LCL;
577: tao->ops->solve = TaoSolve_LCL;
578: tao->ops->view = TaoView_LCL;
579: tao->ops->setfromoptions = TaoSetFromOptions_LCL;
580: tao->ops->destroy = TaoDestroy_LCL;
581: PetscCall(PetscNew(&lclP));
582: tao->data = (void *)lclP;
584: /* Override default settings (unless already changed) */
585: if (!tao->max_it_changed) tao->max_it = 200;
586: if (!tao->catol_changed) tao->catol = 1.0e-4;
587: if (!tao->gatol_changed) tao->gttol = 1.0e-4;
588: if (!tao->grtol_changed) tao->gttol = 1.0e-4;
589: if (!tao->gttol_changed) tao->gttol = 1.0e-4;
590: lclP->rho0 = 1.0e-4;
591: lclP->rhomax = 1e5;
592: lclP->eps1 = 1.0e-8;
593: lclP->eps2 = 0.0;
594: lclP->solve_type = 2;
595: lclP->tau[0] = lclP->tau[1] = lclP->tau[2] = lclP->tau[3] = 1.0e-4;
596: PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch));
597: PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
598: PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type));
599: PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, tao->hdr.prefix));
601: PetscCall(TaoLineSearchSetObjectiveAndGradientRoutine(tao->linesearch, LCLComputeAugmentedLagrangianAndGradient, tao));
602: PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
603: PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
604: PetscCall(KSPSetOptionsPrefix(tao->ksp, tao->hdr.prefix));
605: PetscCall(KSPSetFromOptions(tao->ksp));
607: PetscCall(MatCreate(((PetscObject)tao)->comm, &lclP->R));
608: PetscCall(MatSetType(lclP->R, MATLMVMBFGS));
609: PetscFunctionReturn(PETSC_SUCCESS);
610: }
612: static PetscErrorCode LCLComputeLagrangianAndGradient(TaoLineSearch ls, Vec X, PetscReal *f, Vec G, void *ptr)
613: {
614: Tao tao = (Tao)ptr;
615: TAO_LCL *lclP = (TAO_LCL *)tao->data;
616: PetscBool set, pset, flag, pflag, symmetric;
617: PetscReal cdotl;
619: PetscFunctionBegin;
620: PetscCall(TaoComputeObjectiveAndGradient(tao, X, f, G));
621: PetscCall(LCLScatter(lclP, G, lclP->GU, lclP->GV));
622: if (lclP->recompute_jacobian_flag) {
623: PetscCall(TaoComputeJacobianState(tao, X, tao->jacobian_state, tao->jacobian_state_pre, tao->jacobian_state_inv));
624: PetscCall(TaoComputeJacobianDesign(tao, X, tao->jacobian_design));
625: }
626: PetscCall(TaoComputeConstraints(tao, X, tao->constraints));
627: PetscCall(MatIsSymmetricKnown(tao->jacobian_state, &set, &flag));
628: if (tao->jacobian_state_pre) {
629: PetscCall(MatIsSymmetricKnown(tao->jacobian_state_pre, &pset, &pflag));
630: } else {
631: pset = pflag = PETSC_TRUE;
632: }
633: if (set && pset && flag && pflag) symmetric = PETSC_TRUE;
634: else symmetric = PETSC_FALSE;
636: PetscCall(VecDot(lclP->lambda0, tao->constraints, &cdotl));
637: lclP->lgn = *f - cdotl;
639: /* Gradient of Lagrangian GL = G - J' * lambda */
640: /* WU = A' * WL
641: WV = B' * WL */
642: if (symmetric) {
643: PetscCall(MatMult(tao->jacobian_state, lclP->lambda0, lclP->GL_U));
644: } else {
645: PetscCall(MatMultTranspose(tao->jacobian_state, lclP->lambda0, lclP->GL_U));
646: }
647: PetscCall(MatMultTranspose(tao->jacobian_design, lclP->lambda0, lclP->GL_V));
648: PetscCall(VecScale(lclP->GL_U, -1.0));
649: PetscCall(VecScale(lclP->GL_V, -1.0));
650: PetscCall(VecAXPY(lclP->GL_U, 1.0, lclP->GU));
651: PetscCall(VecAXPY(lclP->GL_V, 1.0, lclP->GV));
652: PetscCall(LCLGather(lclP, lclP->GL_U, lclP->GL_V, lclP->GL));
654: f[0] = lclP->lgn;
655: PetscCall(VecCopy(lclP->GL, G));
656: PetscFunctionReturn(PETSC_SUCCESS);
657: }
659: static PetscErrorCode LCLComputeAugmentedLagrangianAndGradient(TaoLineSearch ls, Vec X, PetscReal *f, Vec G, void *ptr)
660: {
661: Tao tao = (Tao)ptr;
662: TAO_LCL *lclP = (TAO_LCL *)tao->data;
663: PetscReal con2;
664: PetscBool flag, pflag, set, pset, symmetric;
666: PetscFunctionBegin;
667: PetscCall(LCLComputeLagrangianAndGradient(tao->linesearch, X, f, G, tao));
668: PetscCall(LCLScatter(lclP, G, lclP->GL_U, lclP->GL_V));
669: PetscCall(VecDot(tao->constraints, tao->constraints, &con2));
670: lclP->aug = lclP->lgn + 0.5 * lclP->rho * con2;
672: /* Gradient of Aug. Lagrangian GAugL = GL + rho * J' c */
673: /* WU = A' * c
674: WV = B' * c */
675: PetscCall(MatIsSymmetricKnown(tao->jacobian_state, &set, &flag));
676: if (tao->jacobian_state_pre) {
677: PetscCall(MatIsSymmetricKnown(tao->jacobian_state_pre, &pset, &pflag));
678: } else {
679: pset = pflag = PETSC_TRUE;
680: }
681: if (set && pset && flag && pflag) symmetric = PETSC_TRUE;
682: else symmetric = PETSC_FALSE;
684: if (symmetric) {
685: PetscCall(MatMult(tao->jacobian_state, tao->constraints, lclP->GAugL_U));
686: } else {
687: PetscCall(MatMultTranspose(tao->jacobian_state, tao->constraints, lclP->GAugL_U));
688: }
690: PetscCall(MatMultTranspose(tao->jacobian_design, tao->constraints, lclP->GAugL_V));
691: PetscCall(VecAYPX(lclP->GAugL_U, lclP->rho, lclP->GL_U));
692: PetscCall(VecAYPX(lclP->GAugL_V, lclP->rho, lclP->GL_V));
693: PetscCall(LCLGather(lclP, lclP->GAugL_U, lclP->GAugL_V, lclP->GAugL));
695: f[0] = lclP->aug;
696: PetscCall(VecCopy(lclP->GAugL, G));
697: PetscFunctionReturn(PETSC_SUCCESS);
698: }
700: static PetscErrorCode LCLGather(TAO_LCL *lclP, Vec u, Vec v, Vec x)
701: {
702: PetscFunctionBegin;
703: PetscCall(VecScatterBegin(lclP->state_scatter, u, x, INSERT_VALUES, SCATTER_REVERSE));
704: PetscCall(VecScatterEnd(lclP->state_scatter, u, x, INSERT_VALUES, SCATTER_REVERSE));
705: PetscCall(VecScatterBegin(lclP->design_scatter, v, x, INSERT_VALUES, SCATTER_REVERSE));
706: PetscCall(VecScatterEnd(lclP->design_scatter, v, x, INSERT_VALUES, SCATTER_REVERSE));
707: PetscFunctionReturn(PETSC_SUCCESS);
708: }
709: static PetscErrorCode LCLScatter(TAO_LCL *lclP, Vec x, Vec u, Vec v)
710: {
711: PetscFunctionBegin;
712: PetscCall(VecScatterBegin(lclP->state_scatter, x, u, INSERT_VALUES, SCATTER_FORWARD));
713: PetscCall(VecScatterEnd(lclP->state_scatter, x, u, INSERT_VALUES, SCATTER_FORWARD));
714: PetscCall(VecScatterBegin(lclP->design_scatter, x, v, INSERT_VALUES, SCATTER_FORWARD));
715: PetscCall(VecScatterEnd(lclP->design_scatter, x, v, INSERT_VALUES, SCATTER_FORWARD));
716: PetscFunctionReturn(PETSC_SUCCESS);
717: }