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