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