[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
full_space_step.cpp
1 #include "ROL_AugmentedLagrangian.hpp"
2 #include "optimization/full_space_step.hpp"
3 #include "optimization/kkt_operator.hpp"
4 #include "optimization/kkt_birosghattas_preconditioners.hpp"
5 
6 #include "global_counter.hpp"
7 
8 namespace ROL {
9 
10 template <class Real>
13  ROL::ParameterList &parlist,
14  const ROL::Ptr<LineSearch<Real> > &lineSearch,
15  const ROL::Ptr<Secant<Real> > &secant)
16  : Step<Real>()
17  , secant_(secant)
18  , lineSearch_(lineSearch)
19  , els_(LINESEARCH_USERDEFINED)
20  , econd_(CURVATURECONDITION_WOLFE)
21  , verbosity_(0)
22  , parlist_(parlist)
23  , pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0)
24 {
25  // Parse parameter list
26  ROL::ParameterList& Llist = parlist.sublist("Step").sublist("Line Search");
27  ROL::ParameterList& Glist = parlist.sublist("General");
28  econd_ = StringToECurvatureCondition(Llist.sublist("Curvature Condition").get("Type","Strong Wolfe Conditions") );
29  acceptLastAlpha_ = Llist.get("Accept Last Alpha", false);
30  verbosity_ = Glist.get("Print Verbosity",0);
31 
32  preconditioner_name_ = parlist.sublist("Full Space").get("Preconditioner","P4");
34 
35  // Initialize Line Search
36  if (lineSearch_ == ROL::nullPtr) {
37  lineSearchName_ = Llist.sublist("Line-Search Method").get("Type","Backtracking");
38  els_ = StringToELineSearch(lineSearchName_);
39  lineSearch_ = LineSearchFactory<Real>(parlist);
40  }
41  else { // User-defined linesearch provided
42  lineSearchName_ = Llist.sublist("Line-Search Method").get("User Defined Line-Search Name",
43  "Unspecified User Defined Line-Search");
44  }
45 
46  secantName_ = Glist.sublist("Secant").get("Type","Limited-Memory BFGS");
47  esec_ = StringToESecant(secantName_);
48  secant_ = SecantFactory<Real>(parlist);
49 
50 }
51 
52 template <class Real>
54  Vector<Real> &lagrangian_gradient,
55  const Vector<Real> &design_variables,
56  const Vector<Real> &lagrange_mult,
57  const Vector<Real> &objective_gradient,
58  Constraint<Real> &equal_constraints) const
59 {
60  /* Apply adjoint of constraint Jacobian to current multiplier. */
61  Real tol = std::sqrt(ROL_EPSILON<Real>());
62 
63  auto &flow_constraint = (dynamic_cast<PHiLiP::FlowConstraints<PHILIP_DIM>&>(equal_constraints));
64  const double old_CFL = flow_constraint.flow_CFL_;
65  // Lagrangian of the gradient should not be influenced by the constraint regularization (CFL)
66  // Otherwise, you when end magnifying the dual variable values since
67  // dL/dW = dI/dW + \lambda^T (M/dt + dRdW)
68  flow_constraint.flow_CFL_ = 0.0;
69  equal_constraints.applyAdjointJacobian(lagrangian_gradient, lagrange_mult, design_variables, tol);
70  flow_constraint.flow_CFL_ = old_CFL;
71  lagrangian_gradient.plus(objective_gradient);
72 }
73 
74 template <class Real>
76  Vector<Real> &lagrange_mult,
77  const Vector<Real> &design_variables,
78  const Vector<Real> &objective_gradient,
79  Constraint<Real> &equal_constraints) const
80 {
81  Real one(1);
82 
83  /* Form right-hand side of the augmented system. */
84  ROL::Ptr<Vector<Real> > rhs1 = design_variable_cloner_->clone();
85  ROL::Ptr<Vector<Real> > rhs2 = lagrange_variable_cloner_->clone();
86 
87  // rhs1 is the negative gradient of the Lagrangian
88  computeLagrangianGradient(*rhs1, design_variables, lagrange_mult, objective_gradient, equal_constraints);
89  rhs1->scale(-one);
90  // rhs2 is zero
91  rhs2->zero();
92 
93  /* Declare left-hand side of augmented system. */
94  ROL::Ptr<Vector<Real> > lhs1 = design_variable_cloner_->clone();
95  ROL::Ptr<Vector<Real> > lhs2 = lagrange_variable_cloner_->clone();
96 
97  /* Compute linear solver tolerance. */
98  //Real b1norm = rhs1->norm();
99  Real tol = std::sqrt(ROL_EPSILON<Real>());
100 
101  /* Solve augmented system. */
102  const std::vector<Real> augiters = equal_constraints.solveAugmentedSystem(*lhs1, *lhs2, *rhs1, *rhs2, design_variables, tol);
103 
104  /* Return updated Lagrange multiplier. */
105  // lhs2 is the multiplier update
106  lagrange_mult.plus(*lhs2);
107 
108  // // Evaluate the full gradient wrt u
109  // obj_->gradient_1(*dualstate_,*state_,z,tol);
110  // // Solve adjoint equation
111  // con_->applyInverseAdjointJacobian_1(*adjoint_,*dualstate_,*state_,z,tol);
112  // adjoint_->scale(static_cast<Real>(-one));
113 
114 }
115 
116 
117 template <class Real>
119  Vector<Real> &design_variables,
120  const Vector<Real> &gradient,
121  Vector<Real> &lagrange_mult,
122  const Vector<Real> &equal_constraints_values,
123  Objective<Real> &objective,
124  Constraint<Real> &equal_constraints,
125  AlgorithmState<Real> &algo_state )
126 {
127  BoundConstraint<Real> bound_constraints;
128  bound_constraints.deactivate();
129  initialize(
130  design_variables,
131  gradient,
132  lagrange_mult,
133  equal_constraints_values,
134  objective,
135  equal_constraints,
136  bound_constraints, // new argument
137  algo_state);
138 }
139 
140 template <class Real>
142  Vector<Real> &design_variables,
143  const Vector<Real> &gradient,
144  Vector<Real> &lagrange_mult,
145  const Vector<Real> &equal_constraints_values,
146  Objective<Real> &objective,
147  Constraint<Real> &equal_constraints,
148  BoundConstraint<Real> &bound_constraints,
149  AlgorithmState<Real> &algo_state )
150 {
151  pcout << __PRETTY_FUNCTION__ << std::endl;
152  Real tol = ROL_EPSILON<Real>();
153  Real zero(0);
154 
155  // Initialize the algorithm state
156  algo_state.iter = 0;
157  algo_state.nfval = 0;
158  algo_state.ncval = 0;
159  algo_state.ngrad = 0;
160 
161  ROL::Ptr<StepState<Real> > step_state = Step<Real>::getState();
162  design_variable_cloner_ = design_variables.clone();
163  design_variable_cloner_ = gradient.clone();
164  lagrange_variable_cloner_ = lagrange_mult.clone();
165  lagrange_variable_cloner_ = equal_constraints_values.clone();
166 
167  lagrange_mult_search_direction_ = lagrange_mult.clone();
168 
169  // Initialize state descent direction and gradient storage
170  step_state->descentVec = design_variables.clone();
171  step_state->gradientVec = gradient.clone();
172  step_state->constraintVec = equal_constraints_values.clone();
173  step_state->searchSize = zero;
174 
175  // Project design_variables onto bound_constraints set
176  if ( bound_constraints.isActivated() ) {
177  bound_constraints.project(design_variables);
178  }
179  // Update objective function, get value, and get gradient
180  const bool changed_design_variables = true;
181  objective.update(design_variables, changed_design_variables, algo_state.iter);
182  algo_state.value = objective.value(design_variables, tol);
183  algo_state.nfval++;
184  objective.gradient(*(step_state->gradientVec), design_variables, tol);
185  algo_state.ngrad++;
186 
187  // Update equal_constraints.
188  equal_constraints.update(design_variables,true,algo_state.iter);
189  equal_constraints.value(*(step_state->constraintVec), design_variables, zero);
190  algo_state.cnorm = lagrange_variable_cloner_->norm();
191  algo_state.ncval++;
192 
193  //computeInitialLagrangeMultiplier(lagrange_mult, design_variables, *(step_state->gradientVec), equal_constraints);
194  auto &equal_constraints_sim_opt = dynamic_cast<ROL::Constraint_SimOpt<Real>&>(equal_constraints);
195  const auto &objective_ctl_gradient = *(dynamic_cast<const Vector_SimOpt<Real>&>(*(step_state->gradientVec)).get_1());
196  const auto &design_variables_sim_opt = dynamic_cast<ROL::Vector_SimOpt<Real>&>(design_variables);
197  const auto &simulation_variables = *(design_variables_sim_opt.get_1());
198  const auto &control_variables = *(design_variables_sim_opt.get_2());
199  equal_constraints_sim_opt.applyInverseAdjointJacobian_1(lagrange_mult, objective_ctl_gradient, simulation_variables, control_variables, tol);
200  lagrange_mult.scale(-1.0);
201 
202  // Compute gradient of Lagrangian at new multiplier guess.
203  ROL::Ptr<Vector<Real> > lagrangian_gradient = step_state->gradientVec->clone();
204  computeLagrangianGradient(*lagrangian_gradient, design_variables, lagrange_mult, *(step_state->gradientVec), equal_constraints);
205  const auto &lagrangian_gradient_simopt = dynamic_cast<const Vector_SimOpt<Real>&>(*lagrangian_gradient);
206  previous_reduced_gradient_ = lagrangian_gradient_simopt.get_2()->clone();
207  algo_state.ngrad++;
208 
209  auto &flow_constraint = (dynamic_cast<PHiLiP::FlowConstraints<PHILIP_DIM>&>(equal_constraints));
210  //flow_constraint.flow_CFL_ = 1.0/std::pow(algo_state.cnorm, 0.5);
211  //flow_constraint.flow_CFL_ = 1.0/std::pow(lagrangian_gradient->norm(), 1.00);
212  //flow_constraint.flow_CFL_ = -std::max(1.0/std::pow(algo_state.cnorm, 2.0), 100.0);
213  //flow_constraint.flow_CFL_ = -1e-0;
214  flow_constraint.flow_CFL_ = -100;
215 
216  // // Not sure why this is done in ROL_Step.hpp
217  // if ( bound_constraints.isActivated() ) {
218  // ROL::Ptr<Vector<Real> > xnew = design_variables.clone();
219  // xnew->set(design_variables);
220  // xnew->axpy(-one,(step_state->gradientVec)->dual());
221  // bound_constraints.project(*xnew);
222  // xnew->axpy(-one,design_variables);
223  // algo_state.gnorm = xnew->norm();
224  // }
225  // else {
226  // algo_state.gnorm = (step_state->gradientVec)->norm();
227  // }
228 
229  // I don't have to initialize with merit function since it does nothing
230  // with it. But might as well be consistent.
231  penalty_value_ = 1.0;
232  merit_function_ = ROL::makePtr<ROL::AugmentedLagrangian<Real>> (
233  makePtrFromRef<Objective<Real>>(objective),
234  makePtrFromRef<Constraint<Real>>(equal_constraints),
235  lagrange_mult,
237  design_variables,
238  equal_constraints_values,
239  parlist_);
240 
241  // Dummy search direction vector used to initialize the linesearch.
242  ROL::Ptr<Vector<Real> > search_direction_dummy = design_variables.clone();
243  lineSearch_->initialize(design_variables, *search_direction_dummy, gradient, *merit_function_, bound_constraints);
244 }
245 
246 template <class Real>
248  const Vector<Real> &search_direction,
249  const Vector<Real> &lagrange_mult_search_direction,
250  const Vector<Real> &design_variables,
251  const Vector<Real> &objective_gradient,
252  const Vector<Real> &equal_constraints_values,
253  const Vector<Real> &adjoint_jacobian_lagrange,
254  Constraint<Real> &equal_constraints,
255  const Real offset)
256 {
257  pcout << __PRETTY_FUNCTION__ << std::endl;
258  // Biros and Ghattas 2005, Part II
259  // Equation (2.10)
260  Real penalty = objective_gradient.dot(search_direction);
261  penalty += adjoint_jacobian_lagrange.dot(search_direction);
262  penalty += equal_constraints_values.dot(lagrange_mult_search_direction);
263 
264  const ROL::Ptr<Vector<Real>> jacobian_search_direction = equal_constraints_values.clone();
265  Real tol = std::sqrt(ROL_EPSILON<Real>());
266  equal_constraints.applyJacobian(*jacobian_search_direction, search_direction, design_variables, tol);
267 
268  Real denom = jacobian_search_direction->dot(equal_constraints_values);
269 
270  penalty /= denom;
271 
272  // Note that the offset is not on the fraction as in the paper.
273  // The penalty term should always be positive and towards infinity.
274  // It is a mistake from the paper since the numerator and denominator can be
275  // small and negative. Therefore, the positive offset on a small negative
276  // numerator with a small negative denominator might result in a large negative
277  // penalty value.
278  // if (penalty > 0.0) {
279  // penalty += offset;
280  // } else {
281  // penalty = 1.0;
282  // }
283  penalty += offset;
284 
285  return penalty;
286 }
287 
288 template <class Real>
289 template<typename MatrixType, typename VectorType, typename PreconditionerType>
291  MatrixType &matrix_A,
292  VectorType &right_hand_side,
293  VectorType &solution,
294  PreconditionerType &preconditioner)
295  //const PHiLiP::Parameters::LinearSolverParam & param = )
296 {
297  const bool print_kkt_operator = false;
298  const bool print_precond_kkt_operator = false;
299  // This will only work with 1 process.
300  if (print_kkt_operator) {
301  matrix_A.print(right_hand_side);
302  }
303 
304  if (print_precond_kkt_operator) {
305  const int do_full_matrix = (1 == dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD));
306  pcout << "do_full_matrix: " << do_full_matrix << std::endl;
307  if (do_full_matrix) {
308  dealiiSolverVectorWrappingROL<Real> column_of_kkt_operator, column_of_precond_kkt_operator;
309  column_of_kkt_operator.reinit(right_hand_side);
310  column_of_precond_kkt_operator.reinit(right_hand_side);
311  dealii::FullMatrix<double> fullA(right_hand_side.size());
312  for (int i = 0; i < right_hand_side.size(); ++i) {
313  pcout << "COLUMN NUMBER: " << i+1 << " OUT OF " << right_hand_side.size() << std::endl;
314  auto basis = right_hand_side.basis(i);
315  MPI_Barrier(MPI_COMM_WORLD);
316  {
317  matrix_A.vmult(column_of_kkt_operator,*basis);
318  preconditioner.vmult(column_of_precond_kkt_operator,column_of_kkt_operator);
319  }
320  //preconditioner.vmult(column_of_precond_kkt_operator,*basis);
321  if (do_full_matrix) {
322  for (int j = 0; j < right_hand_side.size(); ++j) {
323  fullA[j][i] = column_of_precond_kkt_operator[j];
324  //fullA[j][i] = column_of_kkt_operator[j];
325  }
326  }
327  }
328  pcout<<"Dense matrix:"<<std::endl;
329  fullA.print_formatted(std::cout, 14, true, 10, "0", 1., 0.);
330  std::abort();
331  }
332  }
333 
334  enum Solver_types { gmres, fgmres };
335 
336 
337 
338 
339  const double rhs_norm = right_hand_side.l2_norm();
340  (void) rhs_norm;
341  // const double tolerance = rhs_norm*rhs_norm;
342  //const double tolerance = std::max(1e-8 * rhs_norm, 1e-14);
343 
344  //const double tolerance = std::max(rhs_norm * rhs_norm, 1e-12);
345  //const double tolerance = 1e-11;
346  //const double tolerance = std::max(1e-3 * rhs_norm, 1e-11);
347  // Used for almost all the results:
348  const double tolerance = std::min(1e-4, std::max(1e-6 * rhs_norm, 1e-11));
349 
350  dealii::SolverControl solver_control(2000, tolerance, true, true);
351  solver_control.enable_history_data();
352 
353  (void) preconditioner;
354  const unsigned int max_n_tmp_vectors = 1000;
355  //Solver_types solver_type = gmres;
356  // Used for most results
357  Solver_types solver_type = fgmres;
358  switch(solver_type) {
359 
360  case gmres: {
361  const bool right_preconditioning = true; // default: false
362  const bool use_default_residual = true;//false; // default: true
363  const bool force_re_orthogonalization = false; // default: false
364  typedef typename dealii::SolverGMRES<VectorType>::AdditionalData AddiData_GMRES;
365  AddiData_GMRES add_data_gmres( max_n_tmp_vectors, right_preconditioning, use_default_residual, force_re_orthogonalization);
366  dealii::SolverGMRES<VectorType> solver_gmres(solver_control, add_data_gmres);
367  solution = right_hand_side;
368  try {
369  solver_gmres.solve(matrix_A, solution, right_hand_side
370  //, dealii::PreconditionIdentity());
371  , preconditioner);
372  } catch(...) {
373  }
374  break;
375  }
376  case fgmres: {
377  typedef typename dealii::SolverFGMRES<VectorType>::AdditionalData AddiData_FGMRES;
378  AddiData_FGMRES add_data_fgmres( max_n_tmp_vectors );
379  dealii::SolverFGMRES<VectorType> solver_fgmres(solver_control, add_data_fgmres);
380  try {
381  solver_fgmres.solve(matrix_A, solution, right_hand_side
382  //, dealii::PreconditionIdentity());
383  , preconditioner);
384  } catch(...) {
385  solution = right_hand_side;
386  }
387  break;
388  }
389  default: break;
390  }
391  return solver_control.get_history_data();
392 
393 }
394 
395 template <class Real>
397  Vector<Real> &search_direction,
398  Vector<Real> &lag_search_direction,
399  const Vector<Real> &design_variables,
400  const Vector<Real> &lagrange_mult,
401  Objective<Real> &objective,
402  Constraint<Real> &equal_constraints)
403 {
404  Real tol = std::sqrt(ROL_EPSILON<Real>());
405  const Real one = 1.0;
406 
407  /* Form gradient of the Lagrangian. */
408  ROL::Ptr<Vector<Real> > objective_gradient = design_variable_cloner_->clone();
409  objective.gradient(*objective_gradient, design_variables, tol);
410  // Apply adjoint of equal_constraints Jacobian to current Lagrange multiplier.
411  ROL::Ptr<Vector<Real> > adjoint_jacobian_lagrange = design_variable_cloner_->clone();
412  equal_constraints.applyAdjointJacobian(*adjoint_jacobian_lagrange, lagrange_mult, design_variables, tol);
413 
414  /* Form right-hand side of the augmented system. */
415  ROL::Ptr<Vector<Real> > rhs1 = design_variable_cloner_->clone();
416  ROL::Ptr<Vector<Real> > rhs2 = lagrange_variable_cloner_->clone();
417  // rhs1 is the negative gradient of the Lagrangian
418  computeLagrangianGradient(*rhs1, design_variables, lagrange_mult, *objective_gradient, equal_constraints);
419  rhs1->scale(-one);
420  // rhs2 is the contraint value
421  equal_constraints.value(*rhs2, design_variables, tol);
422  rhs2->scale(-one);
423 
424  //pcout << " norm(rhs1) : " << rhs1->norm() << std::endl;
425  //pcout << " norm(rhs2) : " << rhs2->norm() << std::endl;
426 
427  /* Declare left-hand side of augmented system. */
428  ROL::Ptr<Vector<Real> > lhs1 = rhs1->clone();
429  ROL::Ptr<Vector<Real> > lhs2 = rhs2->clone();
430 
431  ROL::Vector_SimOpt lhs_rol(lhs1, lhs2);
432  ROL::Vector_SimOpt rhs_rol(rhs1, rhs2);
433 
434  KKT_Operator kkt_operator(
435  makePtrFromRef<Objective<Real>>(objective),
436  makePtrFromRef<Constraint<Real>>(equal_constraints),
437  makePtrFromRef<const Vector<Real>>(design_variables),
438  makePtrFromRef<const Vector<Real>>(lagrange_mult));
439 
440 
441  std::shared_ptr<BirosGhattasPreconditioner<Real>> kkt_precond =
443  objective,
444  equal_constraints,
445  design_variables,
446  lagrange_mult,
447  secant_);
448 
449  dealiiSolverVectorWrappingROL<double> lhs(makePtrFromRef(lhs_rol));
450  dealiiSolverVectorWrappingROL<double> rhs(makePtrFromRef(rhs_rol));
451 
452  std::vector<double> linear_residuals = solve_linear (kkt_operator, rhs, lhs, *kkt_precond);
453  pcout << "Solving the KKT system took "
454  << linear_residuals.size() << " iterations "
455  << " to achieve a residual of " << linear_residuals.back() << std::endl;
456 
457  search_direction.set(*(lhs_rol.get_1()));
458  lag_search_direction.set(*(lhs_rol.get_2()));
459 
460  //pcout << " norm(lhs1) : " << search_direction.norm() << std::endl;
461  //pcout << " norm(lhs2) : " << lag_search_direction.norm() << std::endl;
462 
463  // {
464  // kkt_operator.vmult(residual,lhs);
465  // residual.add(-1.0, rhs);
466  // pcout << "linear residual after solve_KKT_system: " << residual.l2_norm() << std::endl;
467 
468  // pcout<<"solution:"<<std::endl;
469  // lhs.print();
470  // pcout<<"right hand side:"<<std::endl;
471  // rhs.print();
472 
473  // // MPI_Barrier(MPI_COMM_WORLD);
474  // // solution.print();
475  // // std::abort();
476  // }
477 
478 
479  return linear_residuals;
480 
481 }
482 
483 template <class Real>
485  Vector<Real> &search_direction,
486  const Vector<Real> &design_variables,
487  const Vector<Real> &lagrange_mult,
488  Objective<Real> &objective,
489  Constraint<Real> &equal_constraints,
490  AlgorithmState<Real> &algo_state )
491 {
492  BoundConstraint<Real> bound_constraints;
493  bound_constraints.deactivate();
494  compute( search_direction, design_variables, lagrange_mult, objective, equal_constraints, bound_constraints, algo_state );
495 }
496 
497 template <class Real>
499  Vector<Real> &search_direction,
500  const Vector<Real> &design_variables,
501  const Vector<Real> &lagrange_mult,
502  Objective<Real> &objective,
503  Constraint<Real> &equal_constraints,
504  BoundConstraint<Real> &bound_constraints,
505  AlgorithmState<Real> &algo_state )
506 {
507  pcout << __PRETTY_FUNCTION__ << std::endl;
508  ROL::Ptr<StepState<Real> > step_state = Step<Real>::getState();
509 
510  Real tol = std::sqrt(ROL_EPSILON<Real>());
511  const Real one = 1.0;
512 
513  /* Form gradient of the Lagrangian. */
514  ROL::Ptr<Vector<Real> > objective_gradient = design_variable_cloner_->clone();
515  objective.gradient(*objective_gradient, design_variables, tol);
516  // Apply adjoint of equal_constraints Jacobian to current Lagrange multiplier.
517  ROL::Ptr<Vector<Real> > adjoint_jacobian_lagrange = design_variable_cloner_->clone();
518  equal_constraints.applyAdjointJacobian(*adjoint_jacobian_lagrange, lagrange_mult, design_variables, tol);
519 
520  /* Form right-hand side of the augmented system. */
521  ROL::Ptr<Vector<Real> > rhs1 = design_variable_cloner_->clone();
522  ROL::Ptr<Vector<Real> > rhs2 = lagrange_variable_cloner_->clone();
523  // rhs1 is the negative gradient of the Lagrangian
524  ROL::Ptr<Vector<Real> > lagrangian_gradient = step_state->gradientVec->clone();
525  computeLagrangianGradient(*lagrangian_gradient, design_variables, lagrange_mult, *objective_gradient, equal_constraints);
526  rhs1->set(*lagrangian_gradient);
527  rhs1->scale(-one);
528  // rhs2 is the contraint value
529  equal_constraints.value(*rhs2, design_variables, tol);
530  rhs2->scale(-one);
531 
532  /* Declare left-hand side of augmented system. */
533  ROL::Ptr<Vector<Real> > lhs1 = design_variable_cloner_->clone();
534  ROL::Ptr<Vector<Real> > lhs2 = lagrange_variable_cloner_->clone();
535 
536  // /* Compute linear solver tolerance. */
537  // Real b1norm = rhs1->norm();
538  // Real tol = setTolOSS(lmhtol_*b1norm);
539 
540  /* Solve augmented system. */
541  //const std::vector<Real> augiters = equal_constraints.solveAugmentedSystem(*lhs1, *lhs2, *rhs1, *rhs2, design_variables, tol);
542  pcout
543  << "Startingto solve augmented system..."
544  << std::endl;
545  //const std::vector<Real> kkt_iters = equal_constraints.solveAugmentedSystem(*lhs1, *lhs2, *rhs1, *rhs2, design_variables, tol);
546  // {
547  // // Top left block times top vector
548  // objective.hessVec(*lhs1, search_direction, design_variables, tol);
549  // rhs1->axpy(-1.0,*lhs1);
550  // equal_constraints.applyAdjointHessian(*lhs1, lagrange_mult, search_direction, design_variables, tol);
551  // rhs1->axpy(-1.0,*lhs1);
552 
553  // // Top right block times bottom vector
554  // equal_constraints.applyAdjointJacobian(*lhs1, *lagrange_mult_search_direction_, design_variables, tol);
555  // rhs1->axpy(-1.0,*lhs1);
556 
557  // // Bottom left left block times top vector
558  // equal_constraints.applyJacobian(*lhs2, search_direction, design_variables, tol);
559  // rhs2->axpy(-1.0,*lhs2);
560  // pcout << "rhs1->norm() before solve " << rhs1->norm() << std::endl;
561  // pcout << "rhs2->norm() before solve " << rhs2->norm() << std::endl;
562  // MPI_Barrier(MPI_COMM_WORLD);
563  // // Reset rhs
564  // // rhs1 is the negative gradient of the Lagrangian
565  // computeLagrangianGradient(*rhs1, design_variables, lagrange_mult, *objective_gradient, equal_constraints);
566  // rhs1->scale(-one);
567  // // rhs2 is the contraint value
568  // equal_constraints.value(*rhs2, design_variables, tol);
569  // rhs2->scale(-one);
570  // }
571  const std::vector<Real> kkt_iters = solve_KKT_system(*lhs1, *lhs2, design_variables, lagrange_mult, objective, equal_constraints);
572 
573  step_state->SPiter = kkt_iters.size();
574  pcout << "Finished solving augmented system..." << std::endl;
575 
576  {
577  search_direction.set(*lhs1);
579  }
580  // std::cout
581  // << "search_direction.norm(): "
582  // << search_direction.norm()
583  // << std::endl;
584  // std::cout
585  // << "lagrange_mult_search_direction_.norm(): "
586  // << lagrange_mult_search_direction_->norm()
587  // << std::endl;
588  // {
589  // // Top left block times top vector
590  // objective.hessVec(*lhs1, search_direction, design_variables, tol);
591  // rhs1->axpy(-1.0,*lhs1);
592  // equal_constraints.applyAdjointHessian(*lhs1, lagrange_mult, search_direction, design_variables, tol);
593  // rhs1->axpy(-1.0,*lhs1);
594 
595  // // Top right block times bottom vector
596  // equal_constraints.applyAdjointJacobian(*lhs1, *lagrange_mult_search_direction_, design_variables, tol);
597  // rhs1->axpy(-1.0,*lhs1);
598 
599  // // Bottom left left block times top vector
600  // equal_constraints.applyJacobian(*lhs2, search_direction, design_variables, tol);
601  // rhs2->axpy(-1.0,*lhs2);
602 
603  // std::cout << "rhs1->norm() after solve " << rhs1->norm() << std::endl;
604  // std::cout << "rhs2->norm() after solve " << rhs2->norm() << std::endl;
605  // MPI_Barrier(MPI_COMM_WORLD);
606  // //std::abort();
607  // }
608 
609  //#pen_ = parlist.sublist("Step").sublist("Augmented Lagrangian").get("Initial Penalty Parameter",ten);
610  /* Create merit function based on augmented Lagrangian */
611  const Real penalty_offset = 10;//1e-4;
613  search_direction,
615  design_variables,
616  *objective_gradient,
617  *(step_state->constraintVec),
618  *adjoint_jacobian_lagrange,
619  equal_constraints,
620  penalty_offset);
621  const auto reduced_gradient = (dynamic_cast<Vector_SimOpt<Real>&>(*lagrangian_gradient)).get_2();
622  penalty_value_ = std::max(1e-0/reduced_gradient->norm(), 1.0);
623  //penalty_value_ = std::max(1e-2/lagrangian_gradient->norm(), 1.0);
624  pcout
625  << "Finished computeAugmentedLagrangianPenalty..."
626  << std::endl;
627  AugmentedLagrangian<Real> &augLag = dynamic_cast<AugmentedLagrangian<Real>&>(*merit_function_);
628 
629  step_state->nfval = 0;
630  step_state->ngrad = 0;
631  Real merit_function_value = 0.0;
632 
633  bool linesearch_success = false;
634  Real fold = 0.0;
635  int n_searches = 0;
636  while (!linesearch_success) {
637 
638  augLag.reset(lagrange_mult, penalty_value_);
639 
640  const bool changed_design_variables = true;
641  merit_function_->update(design_variables, changed_design_variables, algo_state.iter);
642  fold = merit_function_value;
643  ROL::Ptr<Vector<Real> > merit_function_gradient = design_variable_cloner_->clone();
644  merit_function_->gradient( *merit_function_gradient, design_variables, tol );
645  Real directional_derivative_step = merit_function_gradient->dot(search_direction);
646  directional_derivative_step += step_state->constraintVec->dot(*lagrange_mult_search_direction_);
647  pcout
648  << "Penalty value: " << penalty_value_
649  << "Directional_derivative_step (Should be negative for descent direction)"
650  << directional_derivative_step
651  << std::endl;
652  //if (directional_derivative_step > 0.0) {
653  // pcout << "Increasing penalty value to obtain descent direction..." << std::endl;
654  // penalty_value_ *= 2.0;
655  // continue;
656  //}
657 
658  /* Perform line-search */
659  merit_function_value = merit_function_->value(design_variables, tol );
660  pcout
661  << "Performing line search..."
662  << " Initial merit function value = " << merit_function_value
663  << std::endl;
664  lineSearch_->setData(algo_state.gnorm,*merit_function_gradient);
665 
666  n_linesearches = 0;
667  lineSearch_->run(step_state->searchSize,
668  merit_function_value,
670  step_state->ngrad,
671  directional_derivative_step,
672  search_direction,
673  design_variables,
674  *merit_function_,
675  bound_constraints);
676  step_state->nfval += n_linesearches;
677  const int max_line_searches = parlist_.sublist("Step").sublist("Line Search").get("Function Evaluation Limit",20);
678  if (n_linesearches < max_line_searches) {
679  linesearch_success = true;
680  pcout
681  << "End of line search... searchSize is..."
682  << step_state->searchSize
683  << " and number of function evaluations: "
684  << step_state->nfval
685  << " and n_linesearches: "
686  << n_linesearches
687  << " Max linesearches : " << max_line_searches
688  << " Final merit function value = " << merit_function_value
689  << std::endl;
690  } else {
691  n_searches++;
692  Real penalty_reduction = 0.1;
693  pcout
694  << " Max linesearches achieved: " << max_line_searches
695  << " Current merit_function_value value = " << merit_function_value
696  << " Reducing penalty value from " << penalty_value_
697  << " to " << penalty_value_ * penalty_reduction
698  << std::endl;
699  penalty_value_ = penalty_value_ * penalty_reduction;
700 
701  if (n_searches > 1) {
702  pcout << " Linesearch failed, searching other direction " << std::endl;
703  search_direction.scale(-1.0);
704  penalty_value_ = std::max(1e-0/reduced_gradient->norm(), 1.0);
705  }
706  if (n_searches > 2) {
707  pcout << " Linesearch failed in other direction... ending " << std::endl;
708  std::abort();
709  }
710  }
711  lineSearch_->setMaxitUpdate(step_state->searchSize, merit_function_value, fold);
712  }
713 
714  pcout
715  << "End of line search... searchSize is..."
716  << step_state->searchSize
717  << " and number of function evaluations: "
718  << step_state->nfval
719  << " Final merit function value = " << merit_function_value
720  << std::endl;
721 
722  // // Make correction if maximum function evaluations reached
723  // if(!acceptLastAlpha_) {
724  // lineSearch_->setMaxitUpdate(step_state->searchSize,fval_,algo_state.value);
725  // }
726  // Compute scaled descent direction
727  lagrange_mult_search_direction_->scale(step_state->searchSize);
728  search_direction.scale(step_state->searchSize);
729  if ( bound_constraints.isActivated() ) {
730  search_direction.plus(design_variables);
731  bound_constraints.project(search_direction);
732  search_direction.axpy(static_cast<Real>(-1),design_variables);
733  }
734  pcout
735  << "End of compute..."
736  << std::endl;
737 
738 }
739 
740 template <class Real>
742  Vector<Real> &design_variables,
743  Vector<Real> &lagrange_mult,
744  const Vector<Real> &search_direction,
745  Objective<Real> &objective,
746  Constraint<Real> &equal_constraints,
747  AlgorithmState<Real> &algo_state )
748 {
749  pcout << __PRETTY_FUNCTION__ << std::endl;
750  BoundConstraint<Real> bound_constraints;
751  bound_constraints.deactivate();
752  update( design_variables, lagrange_mult, search_direction, objective, equal_constraints, bound_constraints, algo_state );
753 }
754 
755 template <class Real>
757  Vector<Real> &design_variables,
758  Vector<Real> &lagrange_mult,
759  const Vector<Real> &search_direction,
760  Objective<Real> &objective,
761  Constraint<Real> &equal_constraints,
762  BoundConstraint< Real > &bound_constraints,
763  AlgorithmState<Real> &algo_state )
764 {
765  pcout << __PRETTY_FUNCTION__ << std::endl;
766  Real tol = std::sqrt(ROL_EPSILON<Real>());
767  (void) bound_constraints;
768  design_variables.plus(search_direction);
769  lagrange_mult.plus(*lagrange_mult_search_direction_);
770 
771  // Update StepState
772  ROL::Ptr<StepState<Real> > step_state = Step<Real>::getState();
773  step_state->descentVec = design_variables.clone();
774  objective.gradient(*(step_state->gradientVec), design_variables, tol);
775  equal_constraints.value(*(step_state->constraintVec), design_variables, tol);
776 
777 
778  ROL::Ptr<Vector<Real> > lagrangian_gradient = step_state->gradientVec->clone();
779  computeLagrangianGradient(*lagrangian_gradient, design_variables, lagrange_mult, *(step_state->gradientVec), equal_constraints);
780 
781  algo_state.nfval += step_state->nfval;
782  algo_state.ngrad += step_state->ngrad;
783 
784 
785  algo_state.value = objective.value(design_variables, tol);
786  algo_state.gnorm = lagrangian_gradient->norm();
787  algo_state.cnorm = step_state->constraintVec->norm();
788  search_sim_norm = ((dynamic_cast<const Vector_SimOpt<Real>&>(search_direction)).get_1())->norm();
789  search_ctl_norm = ((dynamic_cast<const Vector_SimOpt<Real>&>(search_direction)).get_2())->norm();
791 
792  algo_state.snorm = std::pow(search_sim_norm,2) +
793  std::pow(search_ctl_norm,2) +
794  std::pow(search_adj_norm,2);
795  algo_state.snorm = std::sqrt(algo_state.snorm);
796 
797  auto &flow_constraint = (dynamic_cast<PHiLiP::FlowConstraints<PHILIP_DIM>&>(equal_constraints));
798  //flow_constraint.update(
799  // *((dynamic_cast<const Vector_SimOpt<Real>&>(design_variables)).get_1()),
800  // *((dynamic_cast<const Vector_SimOpt<Real>&>(design_variables)).get_2()),
801  // true,
802  // algo_state.iter); // Prints out the solution.
803  //flow_constraint.flow_CFL_ = 1.0/std::pow(algo_state.cnorm, 0.5);
804  //flow_constraint.flow_CFL_ = 10 + 1.0/std::pow(algo_state.cnorm, 2.0);
805  //flow_constraint.flow_CFL_ = 1.0/std::pow(algo_state.cnorm, 2.0);
806  flow_constraint.flow_CFL_ = -10000*std::max(1.0, 1.0/std::pow(algo_state.cnorm, 2.00));
807  //flow_constraint.flow_CFL_ = 0.0;
808  //flow_constraint.flow_CFL_ = 1e-6;
809 
810  algo_state.iterateVec->set(design_variables);
811  algo_state.lagmultVec->set(lagrange_mult);
812  algo_state.iter++;
813 
814  const auto current_reduced_gradient = (dynamic_cast<Vector_SimOpt<Real>&>(*lagrangian_gradient)).get_2();
815  const auto control_search_direction = (dynamic_cast<const Vector_SimOpt<Real>&>(search_direction)).get_2();
816  const double search_norm = control_search_direction->norm();
817  // Updates if (search.dot(gradDiff) > ROL_EPSILON<Real>()*snorm*snorm) {
818  const double modified_search_norm = std::sqrt(std::pow(search_norm,2) * 1e-8 / ROL_EPSILON<Real>());
819  if (n_linesearches <= 3) {
820  secant_->updateStorage(design_variables, *current_reduced_gradient, *previous_reduced_gradient_, *control_search_direction, modified_search_norm, algo_state.iter+1);
821  }
822  //secant_->updateStorage(design_variables, *current_reduced_gradient, *previous_reduced_gradient_, *control_search_direction, search_norm, algo_state.iter);
823  previous_reduced_gradient_ = current_reduced_gradient;
824 
825  MPI_Barrier(MPI_COMM_WORLD);
826  if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) {
827  pcout
828  << " algo_state.iter: " << algo_state.iter << std::endl
829  << " penalty_value_: "<< penalty_value_ << std::endl
830  << " step_state->searchSize: " << step_state->searchSize << std::endl
831  << " algo_state.value: " << algo_state.value << std::endl
832  << " algo_state.gnorm: " << algo_state.gnorm << std::endl
833  << " algo_state.cnorm: " << algo_state.cnorm << std::endl
834  << " algo_state.snorm: " << algo_state.snorm << std::endl
835  << " n_vmult_total: " << n_vmult << std::endl
836  << " dRdW_form " << dRdW_form << std::endl
837  << " dRdW_mult " << dRdW_mult << std::endl
838  << " dRdX_mult " << dRdX_mult << std::endl
839  << " d2R_mult " << d2R_mult << std::endl
840  ;
841  }
842  MPI_Barrier(MPI_COMM_WORLD);
843 }
844 
845 template <class Real>
847 {
848  //head.erase(std::remove(head.end()-3,head.end(),'\n'), head.end());
849  std::stringstream hist;
850  // hist.write(head.c_str(),head.length());
851  // hist << std::setw(18) << std::left << "ls_#fval";
852  // hist << std::setw(18) << std::left << "ls_#grad";
853  hist << std::setw(18) << std::left << "Iteration";
854  hist << std::setw(18) << std::left << "Func. val.";
855  hist << std::setw(18) << std::left << "||Lagr. grad.||";
856  hist << std::setw(18) << std::left << "||Constraint||";
857  hist << std::setw(18) << std::left << "||Search dir||";
858  hist << std::setw(18) << std::left << "search_ctl_norm";
859  hist << std::setw(18) << std::left << "search_sim_norm";
860  hist << std::setw(18) << std::left << "search_adj_norm";
861  hist << std::setw(18) << std::left << "n_kkt_iter";
862  hist << std::setw(18) << std::left << "n_linesearches";
863  hist << std::setw(18) << std::left << "n_grad";
864  hist << std::setw(18) << std::left << "n_vmult";
865  hist << std::setw(18) << std::left << "dRdW_form";
866  hist << std::setw(18) << std::left << "dRdW_mult";
867  hist << std::setw(18) << std::left << "dRdX_mult";
868  hist << std::setw(18) << std::left << "d2R_mult";
869  hist << "\n";
870  return hist.str();
871 }
872 
873 template <class Real>
875 {
876  std::stringstream hist;
877  //hist << name;
878  hist << "********************************************************" << std::endl;
879  hist << "Biros and Ghattas Full-space method...";
880  hist << "with " + preconditioner_name_ + " preconditioner" << std::endl;
881  const auto &design_variable_simopt = dynamic_cast<const Vector_SimOpt<Real>&>(*design_variable_cloner_);
882  hist << "Using "
883  << design_variable_cloner_->dimension() << " design variables: "
884  << design_variable_simopt.get_1()->dimension() << " simulation variables and "
885  << design_variable_simopt.get_2()->dimension() << " control variables."
886  << std::endl;
887 
888  hist << "Line Search: " << lineSearchName_;
889  hist << " satisfying " << ECurvatureConditionToString(econd_) << "\n";
890  hist << "********************************************************" << std::endl;
891  return hist.str();
892 }
893 
894 template <class Real>
895 std::string FullSpace_BirosGhattas<Real>::print( AlgorithmState<Real> & algo_state, bool print_header) const
896 {
897  const ROL::Ptr<const StepState<Real> > step_state = Step<Real>::getStepState();
898  // desc.erase(std::remove(desc.end()-3,desc.end(),'\n'), desc.end());
899  // size_t pos = desc.find(name);
900  // if ( pos != std::string::npos ) {
901  // desc.erase(pos, name.length());
902  // }
903 
904  std::stringstream hist;
905  if ( algo_state.iter == 0 ) {
906  hist << printName();
907  }
908  (void) print_header;
909  if ( algo_state.iter == 0 ) {
910  //if ( print_header ) {
911  hist << printHeader();
912  }
913  //hist << desc;
914  if ( algo_state.iter == 0 ) {
915  //hist << "\n";
916  }
917  else {
918  hist << std::setw(18) << std::left << algo_state.iter;
919  hist << std::setw(18) << std::left << algo_state.value;
920  hist << std::setw(18) << std::left << algo_state.gnorm;
921  hist << std::setw(18) << std::left << algo_state.cnorm;
922  hist << std::setw(18) << std::left << algo_state.snorm;
923  hist << std::setw(18) << std::left << search_ctl_norm;
924  hist << std::setw(18) << std::left << search_sim_norm;
925  hist << std::setw(18) << std::left << search_adj_norm;
926  hist << std::setw(18) << std::left << step_state->SPiter;
927  hist << std::setw(18) << std::left << step_state->nfval;
928  hist << std::setw(18) << std::left << step_state->ngrad;
929  hist << std::setw(18) << std::left << n_vmult;
930  hist << std::setw(18) << std::left << dRdW_form;
931  hist << std::setw(18) << std::left << dRdW_mult;
932  hist << std::setw(18) << std::left << dRdX_mult;
933  hist << std::setw(18) << std::left << d2R_mult;
934  hist << std::endl;
935  }
936  return hist.str();
937 }
938 
939 template class FullSpace_BirosGhattas<double>;
940 
941 } // ROL namespace
942 
Real penalty_value_
Penalty value of the augmented Lagrangian.
std::string print(AlgorithmState< Real > &algo_state, bool print_header=false) const override
Print iterate status.
virtual void initialize(Vector< Real > &design_variables, const Vector< Real > &gradient, Vector< Real > &lagrange_mult, const Vector< Real > &equal_constraints_values, Objective< Real > &objective, Constraint< Real > &equal_constraints, AlgorithmState< Real > &algo_state) override
Initialize with objective and equality constraints.
ROL::Ptr< Secant< Real > > secant_
Secant object (used for quasi-Newton preconditioner).
ROL::Ptr< LineSearch< Real > > lineSearch_
Line-search object for globalization.
std::string preconditioner_name_
Preconditioner name.
ROL::Ptr< Vector< Real > > lagrange_mult_search_direction_
Lagrange multipliers search direction.
double search_adj_norm
Norm of the adjoint search direction.
void reinit(const dealiiSolverVectorWrappingROL &model_vector, const bool leave_elements_uninitialized=false)
ROL::Ptr< Vector< Real > > lagrange_variable_cloner_
Vector used to clone a vector like the Lagrange variables&#39; / constraints size and parallel distributi...
Wrap the ROL vector into a vector that can be used by deal.II&#39;s solver.
bool acceptLastAlpha_
Whether the last line search&#39;s step length is accepted when the maximum iterations is reached...
ROL::Ptr< Objective< Real > > merit_function_
Merit function used within the line search.
int verbosity_
Print verbosity.
std::string printHeader(void) const override
Print iterate header.
std::string secantName_
Name of secant used as a reduced-Hessian preconditioner.
std::vector< double > solve_linear(MatrixType &matrix_A, VectorType &right_hand_side, VectorType &solution, PreconditionerType &preconditioner)
Solve a linear system using deal.II&#39;s F/GMRES solver.
std::string lineSearchName_
Line search name.
Use DGBase as a Simulation Constraint ROL::Constraint_SimOpt.
void compute(Vector< Real > &search_direction, const Vector< Real > &design_variables, const Vector< Real > &lagrange_mult, Objective< Real > &objective, Constraint< Real > &equal_constraints, AlgorithmState< Real > &algo_state) override
Computes the search directions.
ROL::ParameterList parlist_
Parameter list.
static std::shared_ptr< BirosGhattasPreconditioner< Real > > create_KKT_preconditioner(ROL::ParameterList &parlist, ROL::Objective< Real > &objective, ROL::Constraint< Real > &equal_constraints, const ROL::Vector< Real > &design_variables, const ROL::Vector< Real > &lagrange_mult, const ROL::Ptr< ROL::Secant< Real > > secant_)
Creates a derived preconditioner object, but returns it as BirosGhattasPreconditioner.
ESecant esec_
Enum determines type of secant to use as reduced Hessian preconditioner.
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
FullSpace_BirosGhattas(ROL::ParameterList &parlist, const ROL::Ptr< LineSearch< Real > > &lineSearch=ROL::nullPtr, const ROL::Ptr< Secant< Real > > &secant=ROL::nullPtr)
< See base class.
int n_linesearches
Number of line searches used in the last design cycle.
bool use_approximate_full_space_preconditioner_
Use the Tilde{P} version of Biros and Ghattas&#39; preconditioner.
ROL::Ptr< Vector< Real > > previous_reduced_gradient_
Store previous gradient for secant method.
ECurvatureCondition econd_
Enum determines type of curvature condition.
std::vector< Real > solve_KKT_system(Vector< Real > &search_direction, Vector< Real > &lag_search_direction, const Vector< Real > &design_variables, const Vector< Real > &lagrange_mult, Objective< Real > &objective, Constraint< Real > &equal_constraints)
Setup and solve the large KKT system.
KKT_Operator to be used with dealii::SolverBase class.
Real computeAugmentedLagrangianPenalty(const Vector< Real > &search_direction, const Vector< Real > &lagrange_mult_search_direction, const Vector< Real > &design_variables, const Vector< Real > &objective_gradient, const Vector< Real > &equal_constraints_values, const Vector< Real > &adjoint_jacobian_lagrange, Constraint< Real > &equal_constraints, const Real offset)
Evaluates the penalty of the augmented Lagrangian function using Biros and Ghattas&#39; lower bound...
void computeInitialLagrangeMultiplier(Vector< Real > &lagrange_mult, const Vector< Real > &design_variables, const Vector< Real > &objective_gradient, Constraint< Real > &equal_constraints) const
void computeLagrangianGradient(Vector< Real > &lagrangian_gradient, const Vector< Real > &design_variables, const Vector< Real > &lagrange_mult, const Vector< Real > &objective_gradient, Constraint< Real > &equal_constraints) const
double search_ctl_norm
Norm of the control search direction.
double search_sim_norm
Norm of the simulation search direction.
std::string printName(void) const override
Print step name.
void update(Vector< Real > &design_variables, Vector< Real > &lagrange_mult, const Vector< Real > &search_direction, Objective< Real > &objective, Constraint< Real > &equal_constraints, AlgorithmState< Real > &algo_state) override
Update step, if successful.
ROL::Ptr< Vector< Real > > design_variable_cloner_
Vector used to clone a vector like the design variables&#39; size and parallel distribution.
ELineSearch els_
Enum determines type of line search.