1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20 #include "libmesh/libmesh_common.h"
21
22 #if defined(LIBMESH_HAVE_PETSC_TAO) && !defined(LIBMESH_USE_COMPLEX_NUMBERS)
23
24
25 // C++ includes
26
27 // Local Includes
28 #include "libmesh/libmesh_logging.h"
29 #include "libmesh/petsc_vector.h"
30 #include "libmesh/petsc_matrix.h"
31 #include "libmesh/dof_map.h"
32 #include "libmesh/tao_optimization_solver.h"
33 #include "libmesh/equation_systems.h"
34
35 namespace libMesh
36 {
37
38 //--------------------------------------------------------------------
39 // Functions with C linkage to pass to Tao. Tao will call these
40 // methods as needed.
41 //
42 // Since they must have C linkage they have no knowledge of a namespace.
43 // Give them an obscure name to avoid namespace pollution.
44 extern "C"
45 {
46
47 //---------------------------------------------------------------
48 // This function is called by Tao to evaluate objective function at x
49 PetscErrorCode
__libmesh_tao_objective(Tao,Vec x,PetscReal * objective,void * ctx)50 __libmesh_tao_objective (Tao /*tao*/, Vec x, PetscReal * objective, void * ctx)
51 {
52 LOG_SCOPE("objective()", "TaoOptimizationSolver");
53
54 PetscErrorCode ierr = 0;
55
56 libmesh_assert(x);
57 libmesh_assert(objective);
58 libmesh_assert(ctx);
59
60 // ctx should be a pointer to the solver (it was passed in as void *)
61 TaoOptimizationSolver<Number> * solver =
62 static_cast<TaoOptimizationSolver<Number> *> (ctx);
63
64 OptimizationSystem & sys = solver->system();
65
66 // We'll use current_local_solution below, so let's ensure that it's consistent
67 // with the vector x that was passed in.
68 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
69 PetscVector<Number> X(x, sys.comm());
70
71 // Perform a swap so that sys.solution points to the input vector
72 // "x", update sys.current_local_solution based on "x", then swap
73 // back.
74 X.swap(X_sys);
75 sys.update();
76 X.swap(X_sys);
77
78 // Enforce constraints (if any) exactly on the
79 // current_local_solution. This is the solution vector that is
80 // actually used in the computation of the objective function
81 // below, and is not locked by debug-enabled PETSc the way that
82 // the solution vector is.
83 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
84
85 if (solver->objective_object != nullptr)
86 (*objective) = PS(solver->objective_object->objective(*(sys.current_local_solution), sys));
87 else
88 libmesh_error_msg("Objective function not defined in __libmesh_tao_objective");
89
90 return ierr;
91 }
92
93
94
95 //---------------------------------------------------------------
96 // This function is called by Tao to evaluate the gradient at x
97 PetscErrorCode
__libmesh_tao_gradient(Tao,Vec x,Vec g,void * ctx)98 __libmesh_tao_gradient(Tao /*tao*/, Vec x, Vec g, void * ctx)
99 {
100 LOG_SCOPE("gradient()", "TaoOptimizationSolver");
101
102 PetscErrorCode ierr = 0;
103
104 libmesh_assert(x);
105 libmesh_assert(g);
106 libmesh_assert(ctx);
107
108 // ctx should be a pointer to the solver (it was passed in as void *)
109 TaoOptimizationSolver<Number> * solver =
110 static_cast<TaoOptimizationSolver<Number> *> (ctx);
111
112 OptimizationSystem & sys = solver->system();
113
114 // We'll use current_local_solution below, so let's ensure that it's consistent
115 // with the vector x that was passed in.
116 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
117 PetscVector<Number> X(x, sys.comm());
118
119 // Perform a swap so that sys.solution points to the input vector
120 // "x", update sys.current_local_solution based on "x", then swap
121 // back.
122 X.swap(X_sys);
123 sys.update();
124 X.swap(X_sys);
125
126 // We'll also pass the gradient in to the assembly routine
127 // so let's make a PETSc vector for that too.
128 PetscVector<Number> gradient(g, sys.comm());
129
130 // Clear the gradient prior to assembly
131 gradient.zero();
132
133 // Enforce constraints exactly on the current_local_solution.
134 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
135
136 if (solver->gradient_object != nullptr)
137 solver->gradient_object->gradient(*(sys.current_local_solution), gradient, sys);
138 else
139 libmesh_error_msg("Gradient function not defined in __libmesh_tao_gradient");
140
141 gradient.close();
142
143 return ierr;
144 }
145
146 //---------------------------------------------------------------
147 // This function is called by Tao to evaluate the Hessian at x
148 PetscErrorCode
__libmesh_tao_hessian(Tao,Vec x,Mat h,Mat pc,void * ctx)149 __libmesh_tao_hessian(Tao /*tao*/, Vec x, Mat h, Mat pc, void * ctx)
150 {
151 LOG_SCOPE("hessian()", "TaoOptimizationSolver");
152
153 PetscErrorCode ierr = 0;
154
155 libmesh_assert(x);
156 libmesh_assert(h);
157 libmesh_assert(pc);
158 libmesh_assert(ctx);
159
160 // ctx should be a pointer to the solver (it was passed in as void *)
161 TaoOptimizationSolver<Number> * solver =
162 static_cast<TaoOptimizationSolver<Number> *> (ctx);
163
164 OptimizationSystem & sys = solver->system();
165
166 // We'll use current_local_solution below, so let's ensure that it's consistent
167 // with the vector x that was passed in.
168 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
169 PetscVector<Number> X(x, sys.comm());
170
171 // Perform a swap so that sys.solution points to the input vector
172 // "x", update sys.current_local_solution based on "x", then swap
173 // back.
174 X.swap(X_sys);
175 sys.update();
176 X.swap(X_sys);
177
178 // Let's also wrap pc and h in PetscMatrix objects for convenience
179 PetscMatrix<Number> PC(pc, sys.comm());
180 PetscMatrix<Number> hessian(h, sys.comm());
181 PC.attach_dof_map(sys.get_dof_map());
182 hessian.attach_dof_map(sys.get_dof_map());
183
184 // Enforce constraints exactly on the current_local_solution.
185 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
186
187 if (solver->hessian_object != nullptr)
188 {
189 // Following PetscNonlinearSolver by passing in PC. It's not clear
190 // why we pass in PC and not hessian though?
191 solver->hessian_object->hessian(*(sys.current_local_solution), PC, sys);
192 }
193 else
194 libmesh_error_msg("Hessian function not defined in __libmesh_tao_hessian");
195
196 PC.close();
197 hessian.close();
198
199 return ierr;
200 }
201
202
203 //---------------------------------------------------------------
204 // This function is called by Tao to evaluate the equality constraints at x
205 PetscErrorCode
__libmesh_tao_equality_constraints(Tao,Vec x,Vec ce,void * ctx)206 __libmesh_tao_equality_constraints(Tao /*tao*/, Vec x, Vec ce, void * ctx)
207 {
208 LOG_SCOPE("equality_constraints()", "TaoOptimizationSolver");
209
210 PetscErrorCode ierr = 0;
211
212 libmesh_assert(x);
213 libmesh_assert(ce);
214 libmesh_assert(ctx);
215
216 // ctx should be a pointer to the solver (it was passed in as void *)
217 TaoOptimizationSolver<Number> * solver =
218 static_cast<TaoOptimizationSolver<Number> *> (ctx);
219
220 OptimizationSystem & sys = solver->system();
221
222 // We'll use current_local_solution below, so let's ensure that it's consistent
223 // with the vector x that was passed in.
224 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
225 PetscVector<Number> X(x, sys.comm());
226
227 // Perform a swap so that sys.solution points to the input vector
228 // "x", update sys.current_local_solution based on "x", then swap
229 // back.
230 X.swap(X_sys);
231 sys.update();
232 X.swap(X_sys);
233
234 // We'll also pass the constraints vector ce into the assembly routine
235 // so let's make a PETSc vector for that too.
236 PetscVector<Number> eq_constraints(ce, sys.comm());
237
238 // Clear the gradient prior to assembly
239 eq_constraints.zero();
240
241 // Enforce constraints exactly on the current_local_solution.
242 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
243
244 if (solver->equality_constraints_object != nullptr)
245 solver->equality_constraints_object->equality_constraints(*(sys.current_local_solution), eq_constraints, sys);
246 else
247 libmesh_error_msg("Constraints function not defined in __libmesh_tao_equality_constraints");
248
249 eq_constraints.close();
250
251 return ierr;
252 }
253
254 //---------------------------------------------------------------
255 // This function is called by Tao to evaluate the Jacobian of the
256 // equality constraints at x
257 PetscErrorCode
__libmesh_tao_equality_constraints_jacobian(Tao,Vec x,Mat J,Mat Jpre,void * ctx)258 __libmesh_tao_equality_constraints_jacobian(Tao /*tao*/, Vec x, Mat J, Mat Jpre, void * ctx)
259 {
260 LOG_SCOPE("equality_constraints_jacobian()", "TaoOptimizationSolver");
261
262 PetscErrorCode ierr = 0;
263
264 libmesh_assert(x);
265 libmesh_assert(J);
266 libmesh_assert(Jpre);
267
268 // ctx should be a pointer to the solver (it was passed in as void *)
269 TaoOptimizationSolver<Number> * solver =
270 static_cast<TaoOptimizationSolver<Number> *> (ctx);
271
272 OptimizationSystem & sys = solver->system();
273
274 // We'll use current_local_solution below, so let's ensure that it's consistent
275 // with the vector x that was passed in.
276 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
277 PetscVector<Number> X(x, sys.comm());
278
279 // Perform a swap so that sys.solution points to the input vector
280 // "x", update sys.current_local_solution based on "x", then swap
281 // back.
282 X.swap(X_sys);
283 sys.update();
284 X.swap(X_sys);
285
286 // Let's also wrap J and Jpre in PetscMatrix objects for convenience
287 PetscMatrix<Number> J_petsc(J, sys.comm());
288 PetscMatrix<Number> Jpre_petsc(Jpre, sys.comm());
289
290 // Enforce constraints exactly on the current_local_solution.
291 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
292
293 if (solver->equality_constraints_jacobian_object != nullptr)
294 solver->equality_constraints_jacobian_object->equality_constraints_jacobian(*(sys.current_local_solution), J_petsc, sys);
295 else
296 libmesh_error_msg("Constraints function not defined in __libmesh_tao_equality_constraints_jacobian");
297
298 J_petsc.close();
299 Jpre_petsc.close();
300
301 return ierr;
302 }
303
304 //---------------------------------------------------------------
305 // This function is called by Tao to evaluate the inequality constraints at x
306 PetscErrorCode
__libmesh_tao_inequality_constraints(Tao,Vec x,Vec cineq,void * ctx)307 __libmesh_tao_inequality_constraints(Tao /*tao*/, Vec x, Vec cineq, void * ctx)
308 {
309 LOG_SCOPE("inequality_constraints()", "TaoOptimizationSolver");
310
311 PetscErrorCode ierr = 0;
312
313 libmesh_assert(x);
314 libmesh_assert(cineq);
315 libmesh_assert(ctx);
316
317 // ctx should be a pointer to the solver (it was passed in as void *)
318 TaoOptimizationSolver<Number> * solver =
319 static_cast<TaoOptimizationSolver<Number> *> (ctx);
320
321 OptimizationSystem & sys = solver->system();
322
323 // We'll use current_local_solution below, so let's ensure that it's consistent
324 // with the vector x that was passed in.
325 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
326 PetscVector<Number> X(x, sys.comm());
327
328 // Perform a swap so that sys.solution points to the input vector
329 // "x", update sys.current_local_solution based on "x", then swap
330 // back.
331 X.swap(X_sys);
332 sys.update();
333 X.swap(X_sys);
334
335 // We'll also pass the constraints vector ce into the assembly routine
336 // so let's make a PETSc vector for that too.
337 PetscVector<Number> ineq_constraints(cineq, sys.comm());
338
339 // Clear the gradient prior to assembly
340 ineq_constraints.zero();
341
342 // Enforce constraints exactly on the current_local_solution.
343 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
344
345 if (solver->inequality_constraints_object != nullptr)
346 solver->inequality_constraints_object->inequality_constraints(*(sys.current_local_solution), ineq_constraints, sys);
347 else
348 libmesh_error_msg("Constraints function not defined in __libmesh_tao_inequality_constraints");
349
350 ineq_constraints.close();
351
352 return ierr;
353 }
354
355 //---------------------------------------------------------------
356 // This function is called by Tao to evaluate the Jacobian of the
357 // equality constraints at x
358 PetscErrorCode
__libmesh_tao_inequality_constraints_jacobian(Tao,Vec x,Mat J,Mat Jpre,void * ctx)359 __libmesh_tao_inequality_constraints_jacobian(Tao /*tao*/, Vec x, Mat J, Mat Jpre, void * ctx)
360 {
361 LOG_SCOPE("inequality_constraints_jacobian()", "TaoOptimizationSolver");
362
363 PetscErrorCode ierr = 0;
364
365 libmesh_assert(x);
366 libmesh_assert(J);
367 libmesh_assert(Jpre);
368
369 // ctx should be a pointer to the solver (it was passed in as void *)
370 TaoOptimizationSolver<Number> * solver =
371 static_cast<TaoOptimizationSolver<Number> *> (ctx);
372
373 OptimizationSystem & sys = solver->system();
374
375 // We'll use current_local_solution below, so let's ensure that it's consistent
376 // with the vector x that was passed in.
377 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
378 PetscVector<Number> X(x, sys.comm());
379
380 // Perform a swap so that sys.solution points to the input vector
381 // "x", update sys.current_local_solution based on "x", then swap
382 // back.
383 X.swap(X_sys);
384 sys.update();
385 X.swap(X_sys);
386
387 // Let's also wrap J and Jpre in PetscMatrix objects for convenience
388 PetscMatrix<Number> J_petsc(J, sys.comm());
389 PetscMatrix<Number> Jpre_petsc(Jpre, sys.comm());
390
391 // Enforce constraints exactly on the current_local_solution.
392 sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
393
394 if (solver->inequality_constraints_jacobian_object != nullptr)
395 solver->inequality_constraints_jacobian_object->inequality_constraints_jacobian(*(sys.current_local_solution), J_petsc, sys);
396 else
397 libmesh_error_msg("Constraints function not defined in __libmesh_tao_inequality_constraints_jacobian");
398
399 J_petsc.close();
400 Jpre_petsc.close();
401
402 return ierr;
403 }
404
405 } // end extern "C"
406 //---------------------------------------------------------------------
407
408
409
410 //---------------------------------------------------------------------
411 // TaoOptimizationSolver<> methods
412 template <typename T>
TaoOptimizationSolver(OptimizationSystem & system_in)413 TaoOptimizationSolver<T>::TaoOptimizationSolver (OptimizationSystem & system_in) :
414 OptimizationSolver<T>(system_in),
415 _reason(TAO_CONVERGED_USER) // Arbitrary initial value...
416 {
417 }
418
419
420
421 template <typename T>
~TaoOptimizationSolver()422 TaoOptimizationSolver<T>::~TaoOptimizationSolver ()
423 {
424 this->clear ();
425 }
426
427
428
429 template <typename T>
clear()430 void TaoOptimizationSolver<T>::clear ()
431 {
432 if (this->initialized())
433 {
434 this->_is_initialized = false;
435
436 PetscErrorCode ierr=0;
437
438 ierr = TaoDestroy(&_tao);
439 LIBMESH_CHKERR(ierr);
440 }
441 }
442
443
444
445 template <typename T>
init()446 void TaoOptimizationSolver<T>::init ()
447 {
448 // Initialize the data structures if not done so already.
449 if (!this->initialized())
450 {
451 this->_is_initialized = true;
452
453 PetscErrorCode ierr=0;
454
455 ierr = TaoCreate(this->comm().get(),&_tao);
456 LIBMESH_CHKERR(ierr);
457 }
458 }
459
460 template <typename T>
solve()461 void TaoOptimizationSolver<T>::solve ()
462 {
463 LOG_SCOPE("solve()", "TaoOptimizationSolver");
464
465 this->init ();
466
467 this->system().solution->zero();
468
469 PetscMatrix<T> * hessian = cast_ptr<PetscMatrix<T> *>(this->system().matrix);
470 // PetscVector<T> * gradient = cast_ptr<PetscVector<T> *>(this->system().rhs);
471 PetscVector<T> * x = cast_ptr<PetscVector<T> *>(this->system().solution.get());
472 PetscVector<T> * ceq = cast_ptr<PetscVector<T> *>(this->system().C_eq.get());
473 PetscMatrix<T> * ceq_jac = cast_ptr<PetscMatrix<T> *>(this->system().C_eq_jac.get());
474 PetscVector<T> * cineq = cast_ptr<PetscVector<T> *>(this->system().C_ineq.get());
475 PetscMatrix<T> * cineq_jac = cast_ptr<PetscMatrix<T> *>(this->system().C_ineq_jac.get());
476 PetscVector<T> * lb = cast_ptr<PetscVector<T> *>(&this->system().get_vector("lower_bounds"));
477 PetscVector<T> * ub = cast_ptr<PetscVector<T> *>(&this->system().get_vector("upper_bounds"));
478
479 // Set the starting guess to zero.
480 x->zero();
481
482 PetscErrorCode ierr = 0;
483
484 // Workaround for bug where TaoSetFromOptions *reset*
485 // programmatically set tolerance and max. function evaluation
486 // values when "-tao_type ipm" was specified on the command line: we
487 // call TaoSetFromOptions twice (both before and after setting
488 // custom options programmatically)
489 ierr = TaoSetFromOptions(_tao);
490 LIBMESH_CHKERR(ierr);
491
492 // Set convergence tolerances
493 // f(X) - f(X*) (estimated) <= fatol
494 // |f(X) - f(X*)| (estimated) / |f(X)| <= frtol
495 // ||g(X)|| <= gatol
496 // ||g(X)|| / |f(X)| <= grtol
497 // ||g(X)|| / ||g(X0)|| <= gttol
498 // Command line equivalents: -tao_fatol, -tao_frtol, -tao_gatol, -tao_grtol, -tao_gttol
499 ierr = TaoSetTolerances(_tao,
500 #if PETSC_RELEASE_LESS_THAN(3,7,0)
501 // Releases up to 3.X.Y had fatol and frtol, after that they were removed.
502 // Hopefully we'll be able to know X and Y soon. Guessing at 3.7.0.
503 /*fatol=*/PETSC_DEFAULT,
504 /*frtol=*/PETSC_DEFAULT,
505 #endif
506 /*gatol=*/PETSC_DEFAULT,
507 /*grtol=*/this->objective_function_relative_tolerance,
508 /*gttol=*/PETSC_DEFAULT);
509 LIBMESH_CHKERR(ierr);
510
511 // Set the max-allowed number of objective function evaluations
512 // Command line equivalent: -tao_max_funcs
513 ierr = TaoSetMaximumFunctionEvaluations(_tao, this->max_objective_function_evaluations);
514 LIBMESH_CHKERR(ierr);
515
516 // Set the max-allowed number of optimization iterations.
517 // Command line equivalent: -tao_max_it
518 // Not implemented for now as it seems fairly similar to
519 // ierr = TaoSetMaximumIterations(_tao, 4);
520 // LIBMESH_CHKERR(ierr);
521
522 // Set solution vec and an initial guess
523 ierr = TaoSetInitialVector(_tao, x->vec());
524 LIBMESH_CHKERR(ierr);
525
526 // We have to have an objective function
527 libmesh_assert( this->objective_object );
528
529 // Set routines for objective, gradient, hessian evaluation
530 ierr = TaoSetObjectiveRoutine(_tao, __libmesh_tao_objective, this);
531 LIBMESH_CHKERR(ierr);
532
533 if (this->gradient_object)
534 {
535 ierr = TaoSetGradientRoutine(_tao, __libmesh_tao_gradient, this);
536 LIBMESH_CHKERR(ierr);
537 }
538
539 if (this->hessian_object)
540 {
541 ierr = TaoSetHessianRoutine(_tao, hessian->mat(), hessian->mat(), __libmesh_tao_hessian, this);
542 LIBMESH_CHKERR(ierr);
543 }
544
545 if (this->lower_and_upper_bounds_object)
546 {
547 // Need to actually compute the bounds vectors first
548 this->lower_and_upper_bounds_object->lower_and_upper_bounds(this->system());
549
550 ierr = TaoSetVariableBounds(_tao,
551 lb->vec(),
552 ub->vec());
553 LIBMESH_CHKERR(ierr);
554 }
555
556 if (this->equality_constraints_object)
557 {
558 ierr = TaoSetEqualityConstraintsRoutine(_tao, ceq->vec(), __libmesh_tao_equality_constraints, this);
559 LIBMESH_CHKERR(ierr);
560 }
561
562 if (this->equality_constraints_jacobian_object)
563 {
564 ierr = TaoSetJacobianEqualityRoutine(_tao,
565 ceq_jac->mat(),
566 ceq_jac->mat(),
567 __libmesh_tao_equality_constraints_jacobian,
568 this);
569 LIBMESH_CHKERR(ierr);
570 }
571
572 // Optionally set inequality constraints
573 if (this->inequality_constraints_object)
574 {
575 ierr = TaoSetInequalityConstraintsRoutine(_tao, cineq->vec(), __libmesh_tao_inequality_constraints, this);
576 LIBMESH_CHKERR(ierr);
577 }
578
579 // Optionally set inequality constraints Jacobian
580 if (this->inequality_constraints_jacobian_object)
581 {
582 ierr = TaoSetJacobianInequalityRoutine(_tao,
583 cineq_jac->mat(),
584 cineq_jac->mat(),
585 __libmesh_tao_inequality_constraints_jacobian,
586 this);
587 LIBMESH_CHKERR(ierr);
588 }
589
590 // Check for Tao command line options
591 ierr = TaoSetFromOptions(_tao);
592 LIBMESH_CHKERR(ierr);
593
594 // Perform the optimization
595 ierr = TaoSolve(_tao);
596 LIBMESH_CHKERR(ierr);
597
598 // Enforce constraints exactly now that the solve is done. We have
599 // been enforcing them on the current_local_solution during the
600 // solve, but now need to be sure they are enforced on the parallel
601 // solution vector as well.
602 this->system().get_dof_map().enforce_constraints_exactly(this->system());
603
604 // Store the convergence/divergence reason
605 ierr = TaoGetConvergedReason(_tao, &_reason);
606 LIBMESH_CHKERR(ierr);
607 }
608
609
610 template <typename T>
get_dual_variables()611 void TaoOptimizationSolver<T>::get_dual_variables()
612 {
613 LOG_SCOPE("get_dual_variables()", "TaoOptimizationSolver");
614
615 PetscVector<T> * lambda_eq_petsc =
616 cast_ptr<PetscVector<T> *>(this->system().lambda_eq.get());
617 PetscVector<T> * lambda_ineq_petsc =
618 cast_ptr<PetscVector<T> *>(this->system().lambda_ineq.get());
619
620 Vec lambda_eq_petsc_vec = lambda_eq_petsc->vec();
621 Vec lambda_ineq_petsc_vec = lambda_ineq_petsc->vec();
622
623 PetscErrorCode ierr = 0;
624 ierr = TaoGetDualVariables(_tao,
625 &lambda_eq_petsc_vec,
626 &lambda_ineq_petsc_vec);
627 LIBMESH_CHKERR(ierr);
628 }
629
630
631 template <typename T>
print_converged_reason()632 void TaoOptimizationSolver<T>::print_converged_reason()
633 {
634 libMesh::out << "Tao optimization solver convergence/divergence reason: "
635 << TaoConvergedReasons[this->get_converged_reason()] << std::endl;
636 }
637
638
639
640 template <typename T>
get_converged_reason()641 int TaoOptimizationSolver<T>::get_converged_reason()
642 {
643 PetscErrorCode ierr=0;
644
645 if (this->initialized())
646 {
647 ierr = TaoGetConvergedReason(_tao, &_reason);
648 LIBMESH_CHKERR(ierr);
649 }
650
651 return static_cast<int>(_reason);
652 }
653
654
655 //------------------------------------------------------------------
656 // Explicit instantiations
657 template class TaoOptimizationSolver<Number>;
658
659 } // namespace libMesh
660
661
662
663 #endif // #if defined(LIBMESH_HAVE_PETSC_TAO) && !defined(LIBMESH_USE_COMPLEX_NUMBERS)
664