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