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