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